Author: tilman
Date: Thu Jul 30 08:33:24 2026
New Revision: 1936716

Log:
PDFBOX-4951: add FOP based glyph layout, by Volker Kunert

Added:
   pdfbox/trunk/pdfbox-layout-fop/   (props changed)
   pdfbox/trunk/pdfbox-layout-fop/pom.xml   (contents, props changed)
   pdfbox/trunk/pdfbox-layout-fop/src/
   pdfbox/trunk/pdfbox-layout-fop/src/main/
   pdfbox/trunk/pdfbox-layout-fop/src/main/java/
   pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/
   pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/
   pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/
   pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/
   
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/examples/
   
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/examples/GlyphLayoutHelloWorldFOP.java
      - copied, changed from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/main/java/org/apache/pdfbox/glyphlayout/examples/GlyphLayoutHelloWorldAWT.java
   
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/
   
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/FopStringTextFragment.java
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutFontLoaderFop.java
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutProcessorFop.java
   (contents, props changed)
   pdfbox/trunk/pdfbox-layout-fop/src/test/
   pdfbox/trunk/pdfbox-layout-fop/src/test/appended-resources/
   pdfbox/trunk/pdfbox-layout-fop/src/test/appended-resources/META-INF/
   pdfbox/trunk/pdfbox-layout-fop/src/test/appended-resources/META-INF/LICENSE
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/appended-resources/META-INF/LICENSE
   pdfbox/trunk/pdfbox-layout-fop/src/test/java/
   pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/
   pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/
   pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/
   pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutBidiTest.java
      - copied, changed from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutBidiTest.java
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutDin91379FormTest.java
      - copied, changed from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutDin91379FormTest.java
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutDin91379Test.java
      - copied, changed from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutDin91379Test.java
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutHelloWorldTest.java
      - copied, changed from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutHelloWorldAWTTest.java
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutLigaturesAndKerningTest.java
      - copied, changed from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutLigaturesAndKerningTest.java
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutSMPTest.java
      - copied, changed from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutSMPTest.java
   
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/TestBase.java
      - copied, changed from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/TestBase.java
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/log4j2.xml
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/log4j2.xml
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutBidi.pdf   
(contents, props changed)
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutDIN91379.pdf   
(contents, props changed)
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutDIN91379Form.pdf
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutLigaturesAndKerning.pdf
   (contents, props changed)
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutSMP.pdf   
(contents, props changed)
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/HelloWorld.pdf
      - copied, changed from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/pdf/HelloWorld.pdf
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/PdfForm.pdf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/pdf/PdfForm.pdf
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/Arimo-Regular.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/Arimo-Regular.ttf
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/DejaVuSans.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/DejaVuSans.ttf
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/FiraCode-Regular.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/FiraCode-Regular.ttf
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/Lohit-Bengali.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/Lohit-Bengali.ttf
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansArabic-Regular.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansArabic-Regular.ttf
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansBengali-Regular.ttf
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansMath-Regular.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansMath-Regular.ttf
   
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansThai-Regular.ttf
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansThai-Regular.ttf
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/txt/
   pdfbox/trunk/pdfbox-layout-fop/src/test/resources/txt/GlyphLayoutDIN91379.txt
      - copied unchanged from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/txt/GlyphLayoutDIN91379.txt
Modified:
   pdfbox/trunk/pom.xml

Added: pdfbox/trunk/pdfbox-layout-fop/pom.xml
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ pdfbox/trunk/pdfbox-layout-fop/pom.xml      Thu Jul 30 08:33:24 2026        
(r1936716)
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+! Licensed to the Apache Software Foundation (ASF) under one or more
+! contributor license agreements.  See the NOTICE file distributed with
+! this work for additional information regarding copyright ownership.
+! The ASF licenses this file to You under the Apache License, Version 2.0
+! (the "License"); you may not use this file except in compliance with
+! the License.  You may obtain a copy of the License at
+!
+!      http://www.apache.org/licenses/LICENSE-2.0
+!
+! Unless required by applicable law or agreed to in writing, software
+! distributed under the License is distributed on an "AS IS" BASIS,
+! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+! See the License for the specific language governing permissions and
+! limitations under the License.
+!-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.pdfbox</groupId>
+        <artifactId>pdfbox-parent</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>pdfbox-layout-fop</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache PDFBox Layout FOP</name>
+    <description>
+        The Apache PDFBox library is an open source Java tool for working with 
PDF documents. 
+        This artifact contains classes for script layout with Apache FOP.
+    </description>
+    <inceptionYear>2002</inceptionYear>    
+
+    <scm>
+        
<connection>scm:svn:https://svn.apache.org/repos/asf/pdfbox/trunk/pdfbox-layout-fop</connection>
+        
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/pdfbox/trunk/pdfbox-layout-fop</developerConnection>
+        <url>https://svn.apache.org/viewvc/pdfbox/trunk/pdfbox-layout-fop</url>
+    </scm>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.xmlgraphics</groupId>
+            <artifactId>fop</artifactId>
+            <version>2.11</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        
<Automatic-Module-Name>org.apache.pdfbox.pdfbox-layout-fop</Automatic-Module-Name>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <inputExcludes>
+                        
<inputExclude>src/test/resources/pdf/*.pdf</inputExclude>
+                        
<inputExclude>src/test/resources/txt/GlyphLayoutDIN91379.txt</inputExclude>
+                    </inputExcludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/examples/GlyphLayoutHelloWorldFOP.java
 (from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/main/java/org/apache/pdfbox/glyphlayout/examples/GlyphLayoutHelloWorldAWT.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/main/java/org/apache/pdfbox/glyphlayout/examples/GlyphLayoutHelloWorldAWT.java
   Sat Jul 25 14:39:51 2026        (r1936582, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/examples/GlyphLayoutHelloWorldFOP.java
   Thu Jul 30 08:33:24 2026        (r1936716)
@@ -16,31 +16,32 @@
  */
 package org.apache.pdfbox.glyphlayout.examples;
 
-import java.awt.FontFormatException;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import org.apache.pdfbox.glyphlayout.fop.GlyphLayoutProcessorFop;
 
-import org.apache.pdfbox.glyphlayout.awt.GlyphLayoutFontLoaderAwt;
-import org.apache.pdfbox.glyphlayout.awt.GlyphLayoutProcessorAwt;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.font.PDType0Font;
 
 /**
- * Creates a simple document with a TrueType font using GlyphLayoutProcessorAwt
+ * Creates a simple document with a TrueType font using GlyphLayoutProcessorFop
  * adapted from org.apache.pdfbox.examples.pdmodel.HelloWorldTTF
+ * <p>
+ * This subproject is an alternative to the AWT subproject; DIN 91379 
characters will work, but
+ * complex scripts won't. For most people, the AWT project is the better 
choice.
  */
-public class GlyphLayoutHelloWorldAWT
+public class GlyphLayoutHelloWorldFOP
 {
 
-    public static void main(String[] args) throws IOException, 
FontFormatException
+    public static void main(String[] args) throws IOException
     {
-        new GlyphLayoutHelloWorldAWT().test(args);
+        new GlyphLayoutHelloWorldFOP().test(args);
     }
 
-    public void test(String[] args) throws IOException, FontFormatException
+    public void test(String[] args) throws IOException
     {
         if (args.length != 3)
         {
@@ -57,20 +58,16 @@ public class GlyphLayoutHelloWorldAWT
             PDPage page = new PDPage();
             doc.addPage(page);
 
-            GlyphLayoutProcessorAwt glyphLayoutProcessorAwt = new 
GlyphLayoutProcessorAwt();
+            GlyphLayoutProcessorFop glyphLayoutProcessorFop = new 
GlyphLayoutProcessorFop();
             PDType0Font font;
-            GlyphLayoutFontLoaderAwt.FontOptions fontOptions = new 
GlyphLayoutFontLoaderAwt.FontOptions();
-            // call fontOptions.setKerningOn() for kerning
-            // call fontOptions.setLigaturesOn() for additional ligatures, 
e.g. "ffl", "ffi" etc
-            // however mandatory replacements (e.g. in Bengali, Thai, Arabic) 
are always active
             try (InputStream is = new FileInputStream(ttfPath))
             {
-                font = glyphLayoutProcessorAwt.loadFont(doc, is, fontOptions);
+                font = glyphLayoutProcessorFop.loadFont(doc, is);
             }
 
             try (PDPageContentStream contents = new PDPageContentStream(doc, 
page))
             {
-                contents.setGlyphLayoutProcessor(glyphLayoutProcessorAwt);
+                contents.setGlyphLayoutProcessor(glyphLayoutProcessorFop);
                 contents.beginText();
                 contents.setFont(font, 20);
                 contents.newLineAtOffset(100, 700);

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/FopStringTextFragment.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/FopStringTextFragment.java
   Thu Jul 30 08:33:24 2026        (r1936716)
@@ -0,0 +1,84 @@
+package org.apache.pdfbox.glyphlayout.fop;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import org.apache.fop.fonts.TextFragment;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+/**
+ * Fop TextFragment created from String
+ */
+public class FopStringTextFragment implements TextFragment
+{
+
+    private final String s;
+
+    public FopStringTextFragment(String s)
+    {
+        this.s = s;
+    }
+
+    @Override
+    public CharacterIterator getIterator()
+    {
+        return new StringCharacterIterator(s);
+    }
+
+    @Override
+    public int getBeginIndex()
+    {
+        return 0;
+    }
+
+    @Override
+    public int getEndIndex()
+    {
+        return s.length() - 1;
+    }
+
+    @Override
+    public String getScript()
+    {
+        return "auto";
+    }
+
+    @Override
+    public String getLanguage()
+    {
+        return "none";
+    }
+
+    @Override
+    public int getBidiLevel()
+    {
+        return 0;
+    }
+
+    @Override
+    public char charAt(int i)
+    {
+        return s.charAt(i);
+    }
+
+    @Override
+    public CharSequence subSequence(int i, int i1)
+    {
+        return s.subSequence(i, i1 + 1);
+    }
+}

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutFontLoaderFop.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutFontLoaderFop.java
        Thu Jul 30 08:33:24 2026        (r1936716)
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.glyphlayout.fop;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.fop.apps.io.InternalResourceResolver;
+import org.apache.fop.apps.io.ResourceResolverFactory;
+import org.apache.fop.fonts.EmbeddingMode;
+import org.apache.fop.fonts.EncodingMode;
+import org.apache.fop.fonts.FontLoader;
+import org.apache.fop.fonts.FontUris;
+import org.apache.fop.fonts.MultiByteFont;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.xmlgraphics.io.Resource;
+import org.apache.xmlgraphics.io.ResourceResolver;
+
+
+/**
+ * Loads the PDType0Font and awt.Font for GlyphLayoutProcessorAwt
+ * <p>
+ * Use an object of this class only in one thread.
+ *
+ * @author Volker Kunert
+ */
+public class GlyphLayoutFontLoaderFop
+{
+
+    /**
+     * Mapping from PDFBox font to AWT font
+     */
+    private final Map<PDType0Font, MultiByteFont> fopFontMap = new 
ConcurrentHashMap<>();
+
+    /**
+     * Loads the AWT font needed for layout
+     *
+     * @param pdDocument document
+     * @param inputStream of the font
+     * @param embedSubset
+     * @return pdType0Font PDFBox font
+     * @throws IOException if font can not be loaded
+     */
+    public PDType0Font loadFont(PDDocument pdDocument, InputStream 
inputStream, boolean embedSubset)
+            throws IOException
+    {
+        Objects.requireNonNull(inputStream, "InputStream must not be null");
+        PDType0Font pdType0Font;
+
+        // Copy font stream into memory to read it twice for creation of 
PDType0Font and aww.Font
+        try (ByteArrayInputStream bais = new 
ByteArrayInputStream(inputStream.readAllBytes()))
+        {
+            pdType0Font = PDType0Font.load(pdDocument, bais, embedSubset);
+            bais.reset();
+            loadFopFont(pdType0Font, bais);
+        }
+        return pdType0Font;
+    }
+
+    /**
+     * Loads the Fop font needed for layout
+     *
+     * @param doc document
+     * @param inputStream of the font
+     * @return pdType0Font PDFBox font
+     * @throws IOException if font can not be loaded
+     */
+    public PDType0Font loadFont(PDDocument doc, InputStream inputStream)
+            throws IOException
+    {
+        return loadFont(doc, inputStream, true);
+    }
+
+    /**
+     * Loads the AWT font needed for layout
+     *
+     * @param pdType0Font PDFBox font
+     * @param inputStream of the font file
+     * @throws IOException if font can not be loaded
+     */
+    protected void loadFopFont(PDType0Font pdType0Font, InputStream 
inputStream)
+            throws IOException
+    {
+        if (!fopFontMap.containsKey(pdType0Font))
+        {
+            try
+            {
+                ResourceResolver resourceResolver = new 
FopInputStreamResourceResolver(inputStream);
+                InternalResourceResolver internalResourceResolver = 
ResourceResolverFactory
+                        .createInternalResourceResolver(new 
URI(pdType0Font.getName()), resourceResolver);
+                FontUris fontUris = new FontUris(new 
URI(pdType0Font.getName()), null);
+                MultiByteFont mbf = (MultiByteFont) 
FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO,
+                        EncodingMode.AUTO, true, true,
+                        internalResourceResolver, false, false, false);
+                Objects.requireNonNull(mbf);
+                fopFontMap.put(pdType0Font, mbf);
+            }
+            catch (URISyntaxException ex)
+            {
+                throw new IOException(ex);
+            }
+        }
+    }
+
+    /**
+     * Determines if glyph layout is supported for this font
+     *
+     * @param font PDFBox font
+     * @return true if glyph layout is supported for this font and this font 
is a PDType0Font
+     */
+    public boolean supportsFont(PDFont font)
+    {
+        return fopFontMap.containsKey(font);
+    }
+
+    /**
+     * Gets the corresponding Fop font for the given PDFBox font
+     *
+     * @param font PDFBox font
+     * @return fop font if available
+     */
+    public MultiByteFont getFopFont(PDType0Font font)
+    {
+        return fopFontMap.get(font);
+    }
+
+    /**
+     * Resolver needed to construct a FOP MultibyteFont
+     */
+    static class FopInputStreamResourceResolver implements ResourceResolver
+    {
+        private final InputStream inputStream;
+
+        public FopInputStreamResourceResolver(InputStream inputStream)
+        {
+            this.inputStream = inputStream;
+        }
+
+        @Override
+        public OutputStream getOutputStream(URI arg0) throws IOException
+        {
+            return null;
+        }
+
+        @Override
+        public Resource getResource(URI arg0) throws IOException
+        {
+            return new Resource(inputStream);
+        }
+    }
+}

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutProcessorFop.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/main/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutProcessorFop.java
 Thu Jul 30 08:33:24 2026        (r1936716)
@@ -0,0 +1,362 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.glyphlayout.fop;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.Bidi;
+import java.util.Objects;
+import org.apache.fop.fonts.Font;
+
+import org.apache.fop.fonts.GlyphMapping;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.traits.MinOptMax;
+
+import org.apache.pdfbox.pdmodel.ContentStreamForGlyphLayoutInterface;
+import org.apache.pdfbox.pdmodel.GlyphLayoutProcessorInterface;
+import org.apache.pdfbox.pdmodel.GlyphsAndPositions;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+
+
+/**
+ * Processor for glyph layout using Apache FOP
+ * <p>
+ * Use an object of this class only in one thread.
+ *
+ * @author Volker Kunert
+ */
+public class GlyphLayoutProcessorFop implements GlyphLayoutProcessorInterface
+{
+
+    private final GlyphLayoutFontLoaderFop glyphLayoutFontLoaderFop;
+
+    /*
+        Before you call GlyphMapping.doGlyphMapping to position the glyphs,
+        the font size must be multiplied by this factor. Otherwise, the
+        positioning is wrong.
+     */
+    private final float FOP_FONTSIZE_FACTOR = 1e3f;
+
+    /**
+     * Constructs a GlyphLayoutProcessorFop
+     *
+     */
+    public GlyphLayoutProcessorFop()
+    {
+        this.glyphLayoutFontLoaderFop = new GlyphLayoutFontLoaderFop();
+    }
+
+    /**
+     * Checks if glyphs needed for text are missing in t
+     *
+     * @param text text to be checked
+     * @param mbf font to be checked
+     * @throws IllegalArgumentException if glyphs are missing
+     */
+    public static void checkMissingGlyphs(String text, MultiByteFont mbf)
+    {
+        int[] codePoints = text.codePoints().toArray();
+        for (int cp : codePoints)
+        {
+            if (mbf.findGlyphIndex(cp) == 0)
+            {
+                String s = new String(new int[]{cp}, 0, 1);
+                throw new IllegalArgumentException(
+                        String.format("Missing glyph in font '%s' for the 
character '%s', codePoint: %d (U+%04x).",
+                                mbf.getFontName(), s, cp, cp));
+            }
+        }
+    }
+
+    /**
+     * Checks if the font is supported
+     * <p>
+     * This class supports OpenType fonts with description of glyphs as 
TrueType outlines, i.e.
+     * *.ttf-files. *.otf-files using CFF outlines are not supported by PDFBox
+     *
+     * @param font to be checked
+     * @return true if glyph layout is supported for this font and this font 
is a PDType0Font
+     */
+    @Override
+    public boolean supportsFont(PDFont font)
+    {
+        return glyphLayoutFontLoaderFop.supportsFont(font);
+    }
+
+    /**
+     * Loads the font needed for layout
+     *
+     * @param pdDocument document
+     * @param inputStream of the font
+     * @param embedSubset must be false for PDF forms
+     * @throws IOException if font can not be loaded
+     */
+    public PDType0Font loadFont(PDDocument pdDocument, InputStream 
inputStream, boolean embedSubset) throws IOException
+    {
+        return glyphLayoutFontLoaderFop.loadFont(pdDocument, inputStream, 
embedSubset);
+    }
+
+    /**
+     * Loads the AWT font needed for layout
+     *
+     * @param pdDocument document
+     * @param inputStream of the font
+     * @throws IOException if font can not be loaded
+     */
+    public PDType0Font loadFont(PDDocument pdDocument, InputStream 
inputStream) throws IOException
+    {
+        return glyphLayoutFontLoaderFop.loadFont(pdDocument, inputStream, 
true);
+    }
+
+    /**
+     * Computes glyph positioning
+     *
+     * @param font to be used
+     * @param fontSize font size
+     * @param text text to show
+     * @param bidiLevel
+     */
+    protected GlyphMapping computeGlyphAndPositions(PDType0Font font, float 
fontSize, String text, int bidiLevel)
+    {
+        Objects.requireNonNull(font, "Font must be set");
+        Objects.requireNonNull(text, "Text must be set");
+
+        MultiByteFont mbf = glyphLayoutFontLoaderFop.getFopFont(font);
+
+        checkMissingGlyphs(text, mbf);
+
+        MinOptMax letterSpaceIPD = MinOptMax.getInstance(0);
+        MinOptMax[] letterSpaceAdjustArray = new MinOptMax[text.length()];
+
+        org.apache.fop.fonts.Font fopFont = new Font(mbf.getFontName(), null, 
mbf, (int) (fontSize * FOP_FONTSIZE_FACTOR));
+
+        return GlyphMapping.doGlyphMapping(
+                new FopStringTextFragment(text), 0, text.length() - 1, fopFont,
+                letterSpaceIPD, letterSpaceAdjustArray, ' ',
+                ' ', //?
+                false, bidiLevel, false, true, false);
+    }
+
+    /**
+     * Converts the codepoints of the text to glyph ids
+     *
+     * @param font the font to be used
+     * @param text the text to be converted
+     * @return glyph ids with respect to font
+     */
+    protected int[] convertCharsToGlyphIds(PDType0Font font, String text)
+    {
+        MultiByteFont mbf = glyphLayoutFontLoaderFop.getFopFont(font);
+        return text.codePoints().map(cp -> mbf.findGlyphIndex(cp)).toArray();
+    }
+
+    /**
+     * Shows a text using glyph positioning (if needed)
+     *
+     * @param contentStream the content stream
+     * @param font to be used
+     * @param fontSize font size
+     * @param text text to show
+     * @throws IOException if an I/O exception occurs
+     * @throws IllegalArgumentException if glyphs are missing
+     */
+    @Override
+    public void showText(ContentStreamForGlyphLayoutInterface contentStream, 
PDType0Font font, float fontSize, String text) throws IOException
+    {
+        Objects.requireNonNull(text, "Text must be set");
+
+        if (Bidi.requiresBidi(text.toCharArray(), 0, text.length()))
+        {
+            Bidi bidi = new Bidi(text, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+            if (bidi.isMixed())
+            {
+                // Split and Reorder
+                // See PDFTextStripper.handleDirection
+                // collect individual bidi information
+                int runCount = bidi.getRunCount();
+                byte[] levels = new byte[runCount];
+                Integer[] runs = new Integer[runCount];
+
+                for (int i = 0; i < runCount; i++)
+                {
+                    levels[i] = (byte) bidi.getRunLevel(i);
+                    runs[i] = i;
+                }
+                // reorder individual parts based on their levels
+                Bidi.reorderVisually(levels, 0, runs, 0, runCount);
+
+                for (int i = 0; i < runCount; i++)
+                {
+                    int index = runs[i];
+                    int start = bidi.getRunStart(index);
+                    int limit = bidi.getRunLimit(index);
+                    int bidiLevel = levels[index];
+
+                    // Map to correct value for GlyphMapping.doGlyphMapping
+                    // 0 LTR equal in java.text.Bidi and 
org.apache.fop.traits.Direction
+                    // 1 RTL equal in java.text.Bidi and 
org.apache.fop.traits.Direction
+                    bidiLevel = bidiLevel % 2; // even LTR, odd RTL
+                    String part = text.substring(start, limit);
+                    showTextUni(contentStream, font, fontSize, part, 
bidiLevel);
+                }
+            }
+            else
+            {
+                showTextUni(contentStream, font, fontSize, text, 
bidi.getBaseLevel());
+            }
+        }
+        else
+        {
+            showTextUni(contentStream, font, fontSize, text, 
Bidi.DIRECTION_LEFT_TO_RIGHT);
+        }
+    }
+
+    /**
+     * Shows a text using FOP positioning
+     *
+     * @param contentStream
+     * @param font
+     * @param text the text to show
+     * @param fontSize
+     * @param bidiLevel
+     * @throws IOException if an I/O error occurs
+     */
+    protected void showTextUni(ContentStreamForGlyphLayoutInterface 
contentStream, PDType0Font font, float fontSize,
+            String text, int bidiLevel) throws IOException
+    {
+
+        Objects.requireNonNull(text, "Text must be set");
+        Objects.requireNonNull(contentStream, "contentStream must be set");
+
+        GlyphMapping glyphMapping = computeGlyphAndPositions(font, fontSize, 
text, bidiLevel);
+
+        text = glyphMapping.mapping == null ? text : glyphMapping.mapping;
+
+        int[][] gpa = glyphMapping.gposAdjustments != null ? 
glyphMapping.gposAdjustments : createZeroGpa(text.length());
+
+        if (bidiLevel == Bidi.DIRECTION_RIGHT_TO_LEFT)
+        {
+            gpa = reverseGpa(gpa);
+            text = new StringBuilder(text).reverse().toString();
+        }
+        int[] glyphIds = convertCharsToGlyphIds(font, text);
+
+        if (glyphIds.length != text.length())
+        {
+            if (glyphMapping.gposAdjustments == null)
+            {
+                gpa = createZeroGpa(glyphIds.length);
+            }
+            else
+            {
+                // This case:
+                // letters from the supplementary multilingual plane AND 
position adjustments
+                // is not implemented
+                throw new IllegalStateException("glyphIds.length != 
text.length() and gposAdjustments!=null"
+                        + glyphIds.length + " " + text.length() + " " + text);
+            }
+        }
+
+        final float delta = Math.ulp(fontSize); // do only adjustments bigger 
than or equal to one ulp of the font size
+        GlyphsAndPositions ga = new GlyphsAndPositions();
+
+        for (int i = 0; i < glyphIds.length; i++)
+        {
+            // 4-tuples of placement [PX,PY] and advance [AX,AY] adjustments, 
in that order,
+            float px = gpa[i][0] / fontSize * 1000f / FOP_FONTSIZE_FACTOR;
+            float py = gpa[i][1] / FOP_FONTSIZE_FACTOR;
+            float ax = gpa[i][2] / fontSize * 1000f / FOP_FONTSIZE_FACTOR;
+            float ay = gpa[i][3] / FOP_FONTSIZE_FACTOR; // ignored in 
horizontal typesetting
+
+            if (Math.abs(py) >= delta)
+            {
+                if (!ga.isEmpty())
+                {
+                    contentStream.showGlyphsWithPositioning(ga);
+                    ga.clear();
+                }
+                contentStream.setTextRise(py);
+            }
+            if (Math.abs(px) >= delta)
+            {
+                ga.add(-px);
+            }
+            ga.add(glyphIds[i]);
+
+            if (Math.abs(px) >= delta)
+            {
+                ga.add(px);
+            }
+            if (Math.abs(ax) >= delta)
+            {
+                ga.add(-ax);
+            }
+            if (Math.abs(py) >= delta)
+            {
+                contentStream.showGlyphsWithPositioning(ga);
+                ga.clear();
+                contentStream.setTextRise(0.0f);
+            }
+            if (Math.abs(ax) >= delta)
+            {
+                ga.add(ax);
+            }
+        }
+        if (!ga.isEmpty())
+        {
+            contentStream.showGlyphsWithPositioning(ga);
+            ga.clear();
+        }
+    }
+
+    /**
+     * Create a gpa with no corrections
+     *
+     * @param length of the text
+     * @return gpa filled with zeroes
+     */
+    protected int[][] createZeroGpa(int length)
+    {
+        int[][] gpa = new int[length][];
+        int[] z4 = new int[] { 0, 0, 0, 0 };
+        for (int i = 0; i < length; i++)
+        {
+            gpa[i] = z4;
+        }
+        return gpa;
+    }
+
+    /**
+     * Reverse gpa
+     *
+     * @param gpa positioning parameters
+     * @return reversed gpa
+     */
+    protected int[][] reverseGpa(int[][] gpa)
+    {
+        int[][] reversed = new int[gpa.length][];
+
+        for (int i = 0; i < gpa.length; i++)
+        {
+            int r = gpa.length - i - 1;
+            reversed[r] = gpa[i];
+        }
+        return reversed;
+    }
+}

Copied: 
pdfbox/trunk/pdfbox-layout-fop/src/test/appended-resources/META-INF/LICENSE 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/appended-resources/META-INF/LICENSE)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ pdfbox/trunk/pdfbox-layout-fop/src/test/appended-resources/META-INF/LICENSE 
Thu Jul 30 08:33:24 2026        (r1936716, copy of r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/appended-resources/META-INF/LICENSE)
@@ -0,0 +1,294 @@
+Lohit fonts (https://pagure.io/lohit):
+
+    Copyright 2011-15 Lohit Fonts Project contributors
+
+    This Font Software is licensed under the SIL Open Font License, Version 
1.1.
+    This license is copied below, and is also available with a FAQ at:
+    http://scripts.sil.org/OFL
+
+
+    -----------------------------------------------------------
+    SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+    -----------------------------------------------------------
+
+    PREAMBLE
+    The goals of the Open Font License (OFL) are to stimulate worldwide
+    development of collaborative font projects, to support the font creation
+    efforts of academic and linguistic communities, and to provide a free and
+    open framework in which fonts may be shared and improved in partnership
+    with others.
+
+    The OFL allows the licensed fonts to be used, studied, modified and
+    redistributed freely as long as they are not sold by themselves. The
+    fonts, including any derivative works, can be bundled, embedded, 
+    redistributed and/or sold with any software provided that any reserved
+    names are not used by derivative works. The fonts and derivatives,
+    however, cannot be released under any other type of license. The
+    requirement for fonts to remain under this license does not apply
+    to any document created using the fonts or their derivatives.
+
+    DEFINITIONS
+    "Font Software" refers to the set of files released by the Copyright
+    Holder(s) under this license and clearly marked as such. This may
+    include source files, build scripts and documentation.
+
+    "Reserved Font Name" refers to any names specified as such after the
+    copyright statement(s).
+
+    "Original Version" refers to the collection of Font Software components as
+    distributed by the Copyright Holder(s).
+
+    "Modified Version" refers to any derivative made by adding to, deleting,
+    or substituting -- in part or in whole -- any of the components of the
+    Original Version, by changing formats or by porting the Font Software to a
+    new environment.
+
+    "Author" refers to any designer, engineer, programmer, technical
+    writer or other person who contributed to the Font Software.
+
+    PERMISSION & CONDITIONS
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of the Font Software, to use, study, copy, merge, embed, modify,
+    redistribute, and sell modified and unmodified copies of the Font
+    Software, subject to the following conditions:
+
+    1) Neither the Font Software nor any of its individual components,
+    in Original or Modified Versions, may be sold by itself.
+
+    2) Original or Modified Versions of the Font Software may be bundled,
+    redistributed and/or sold with any software, provided that each copy
+    contains the above copyright notice and this license. These can be
+    included either as stand-alone text files, human-readable headers or
+    in the appropriate machine-readable metadata fields within text or
+    binary files as long as those fields can be easily viewed by the user.
+
+    3) No Modified Version of the Font Software may use the Reserved Font
+    Name(s) unless explicit written permission is granted by the corresponding
+    Copyright Holder. This restriction only applies to the primary font name as
+    presented to the users.
+
+    4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+    Software shall not be used to promote, endorse or advertise any
+    Modified Version, except to acknowledge the contribution(s) of the
+    Copyright Holder(s) and the Author(s) or with their explicit written
+    permission.
+
+    5) The Font Software, modified or unmodified, in part or in whole,
+    must be distributed entirely under this license, and must not be
+    distributed under any other license. The requirement for fonts to
+    remain under this license does not apply to any document created
+    using the Font Software.
+
+    TERMINATION
+    This license becomes null and void if any of the above conditions are
+    not met.
+
+    DISCLAIMER
+    THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+    OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+    COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+    INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+    DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+    OTHER DEALINGS IN THE FONT SOFTWARE.
+
+
+FiraCode font:
+
+Copyright (c) 2014, The Fira Code Project Authors 
(https://github.com/tonsky/FiraCode)
+SIL Open Font License, see above
+
+
+NotoSans Arabic font:
+
+Copyright 2022 The Noto Project Authors (https://github.com/notofonts/arabic) 
+SIL Open Font License, see above
+
+
+Arimo font:
+
+Copyright 2026 The Arimo Project Authors 
(https://github.com/googlefonts/arimo) 
+SIL Open Font License, see above
+
+
+NotoSans Math font:
+
+Copyright 2022 The Noto Project Authors (https://github.com/notofonts/math)
+SIL Open Font License, see above
+
+
+NotoSans Thai font:
+Copyright 2022 The Noto Project Authors (https://github.com/notofonts/thai)
+
+
+Licenses for DejaVu font(s) (see also 
https://www.apache.org/legal/resolved.html ):
+
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
+
+
+Bitstream Vera Fonts Copyright
+------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
+a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall
+be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words "Bitstream" or the word
+"Vera".
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the "Bitstream
+Vera" names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font Software
+without prior written authorization from the Gnome Foundation or Bitstream
+Inc., respectively. For further information, contact: fonts at gnome dot org.
+
+Arev Fonts Copyright
+------------------------------
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the 
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free . fr.
+
+TeX Gyre DJV Math
+-----------------
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+
+Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski
+(on behalf of TeX users groups) are in public domain.
+
+Letters imported from Euler Fraktur from AMSfonts are (c) American 
Mathematical Society (see below).
+Bitstream Vera Fonts Copyright
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera
+is a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license (“Fonts”) and associated documentation
+files (the “Font Software”), to reproduce and distribute the Font Software,
+including without limitation the rights to use, copy, merge, publish, 
distribute,
+and/or sell copies of the Font Software, and to permit persons  to whom
+the Font Software is furnished to do so, subject to the following conditions:
+
+The above copyright and trademark notices and this permission notice shall be
+included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and additional
+glyphs or characters may be added to the Fonts, only if the fonts are renamed
+to names not containing either the words “Bitstream” or the word “Vera”.
+
+This License becomes null and void to the extent applicable to Fonts or Font 
Software
+that has been modified and is distributed under the “Bitstream Vera” names.
+
+The Font Software may be sold as part of a larger software package but no copy
+of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
+SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO 
USE
+THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+Except as contained in this notice, the names of GNOME, the GNOME Foundation,
+and Bitstream Inc., shall not be used in advertising or otherwise to promote
+the sale, use or other dealings in this Font Software without prior written
+authorization from the GNOME Foundation or Bitstream Inc., respectively.
+For further information, contact: fonts at gnome dot org.
+
+AMSFonts (v. 2.2) copyright
+
+The PostScript Type 1 implementation of the AMSFonts produced by and
+previously distributed by Blue Sky Research and Y&Y, Inc. are now freely
+available for general use. This has been accomplished through the cooperation
+of a consortium of scientific publishers with Blue Sky Research and Y&Y.
+Members of this consortium include:
+
+Elsevier Science IBM Corporation Society for Industrial and Applied
+Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS)
+
+In order to assure the authenticity of these fonts, copyright will be held by
+the American Mathematical Society. This is not meant to restrict in any way
+the legitimate use of the fonts, such as (but not limited to) electronic
+distribution of documents containing these fonts, inclusion of these fonts
+into other public domain or commercial font collections or computer
+applications, use of the outline data to create derivative fonts and/or
+faces, etc. However, the AMS does require that the AMS copyright notice be
+removed from any derivative versions of the fonts which have been altered in
+any way. In addition, to ensure the fidelity of TeX documents using Computer
+Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces,
+has requested that any alterations which yield different font metrics be
+given a different name.
\ No newline at end of file

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutBidiTest.java
 (from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutBidiTest.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutBidiTest.java
     Mon Jul  6 08:32:53 2026        (r1935929, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutBidiTest.java
     Thu Jul 30 08:33:24 2026        (r1936716)
@@ -14,11 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
 
 import org.junit.jupiter.api.Test;
 
-import java.awt.FontFormatException;
 import java.io.IOException;
 import java.net.URISyntaxException;
 
@@ -28,7 +27,7 @@ import org.apache.pdfbox.pdmodel.PDPageC
 import org.apache.pdfbox.pdmodel.font.PDType0Font;
 
 /**
- * Examples for bidirectional text with GlyphLayoutProcessorAwt
+ * Examples for bidirectional text with GlyphLayoutProcessorFop
  *
  * @author Volker Kunert
  */
@@ -74,9 +73,9 @@ public class GlyphLayoutBidiTest extends
     }
 
     @Test
-    void testGlyphLayoutBidi() throws IOException, FontFormatException, 
URISyntaxException
+    void testGlyphLayoutBidi() throws IOException, URISyntaxException
     {
-        GlyphLayoutProcessorAwt glyphLayoutProcessorAwt = new 
GlyphLayoutProcessorAwt();
+        GlyphLayoutProcessorFop glyphLayoutProcessorFop = new 
GlyphLayoutProcessorFop();
 
         String outputName = "GlyphLayoutBidi.pdf";
         String outputFilename = "target/" + outputName;
@@ -87,14 +86,14 @@ public class GlyphLayoutBidiTest extends
 
         try (PDDocument doc = new PDDocument())
         {
-            PDType0Font arabicFont = 
createPdType0Font(glyphLayoutProcessorAwt, doc, arabicPath);
-            PDType0Font lgcFont = createPdType0Font(glyphLayoutProcessorAwt, 
doc, lgcPath);
+            PDType0Font arabicFont = 
createPdType0Font(glyphLayoutProcessorFop, doc, arabicPath);
+            PDType0Font lgcFont = createPdType0Font(glyphLayoutProcessorFop, 
doc, lgcPath);
 
             PDPage page = new PDPage();
             doc.addPage(page);
             try (PDPageContentStream cs = new PDPageContentStream(doc, page))
             {
-                cs.setGlyphLayoutProcessor(glyphLayoutProcessorAwt);
+                cs.setGlyphLayoutProcessor(glyphLayoutProcessorFop);
                 
                 float x = page.getBBox().getLowerLeftX() + fontSize;
                 float y = page.getBBox().getUpperRightY() - fontSize;

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutDin91379FormTest.java
 (from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutDin91379FormTest.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutDin91379FormTest.java
     Mon Jul  6 08:32:53 2026        (r1935929, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutDin91379FormTest.java
     Thu Jul 30 08:33:24 2026        (r1936716)
@@ -14,9 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
 
-import java.awt.FontFormatException;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -86,9 +85,9 @@ class GlyphLayoutDin91379FormTest extend
                     + "Additional non-letters (not included in DIN 91379): – — 
•�";
 
     @Test
-    void testGlyphLayoutDin91379Form() throws IOException, 
FontFormatException, URISyntaxException
+    void testGlyphLayoutDin91379Form() throws IOException, URISyntaxException
     {
-        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+        GlyphLayoutProcessorFop glyphLayoutProcessor = new 
GlyphLayoutProcessorFop();
 
         String outputName = "GlyphLayoutDIN91379Form.pdf";
         String outputFilename = "target/" + outputName;
@@ -101,9 +100,7 @@ class GlyphLayoutDin91379FormTest extend
         try (PDDocument doc = Loader.loadPDF(pdfForm))
         {
             // embedSubset has to be set to false
-            // last parameter is just for test coverage
-            PDType0Font font = glyphLayoutProcessor.loadFont(doc, fontStream, 
-                    false, new GlyphLayoutFontLoaderAwt.FontOptions());
+            PDType0Font font = glyphLayoutProcessor.loadFont(doc, fontStream,  
false);
 
             PDDocumentCatalog docCatalog = doc.getDocumentCatalog();
             PDAcroForm acroForm = docCatalog.getAcroForm();

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutDin91379Test.java
 (from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutDin91379Test.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutDin91379Test.java
 Mon Jul  6 08:32:53 2026        (r1935929, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutDin91379Test.java
 Thu Jul 30 08:33:24 2026        (r1936716)
@@ -14,9 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
 
-import java.awt.FontFormatException;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -26,16 +25,17 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.net.URISyntaxException;
-import org.apache.pdfbox.Loader;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
 
+import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.font.PDType0Font;
 import org.apache.pdfbox.text.PDFTextStripper;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
  * Example of formatting for letters defined in: DIN 91379: Characters in 
Unicode for the electronic
@@ -91,9 +91,9 @@ class GlyphLayoutDin91379Test extends Te
                     + "Additional non-letters (not included in DIN 91379): – — 
•�";
 
     @Test
-    void testGlyphLayoutDin91379() throws IOException, FontFormatException, 
URISyntaxException
+    void testGlyphLayoutDin91379() throws IOException, URISyntaxException
     {
-        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+        GlyphLayoutProcessorFop glyphLayoutProcessor = new 
GlyphLayoutProcessorFop();
 
         String outputName = "GlyphLayoutDIN91379.pdf";
         String outputPDFFilename = "target/" + outputName;

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutHelloWorldTest.java
 (from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutHelloWorldAWTTest.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutHelloWorldAWTTest.java
    Sat Jul 25 14:39:51 2026        (r1936582, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutHelloWorldTest.java
       Thu Jul 30 08:33:24 2026        (r1936716)
@@ -14,31 +14,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
 
-import java.awt.FontFormatException;
 import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
 
 import org.junit.jupiter.api.Test;
 
-import org.apache.pdfbox.glyphlayout.examples.GlyphLayoutHelloWorldAWT;
+import org.apache.pdfbox.glyphlayout.examples.GlyphLayoutHelloWorldFOP;
 
 /**
  *
  * @author Tilman Hausherr
  */
-class GlyphLayoutHelloWorldAWTTest extends TestBase
+class GlyphLayoutHelloWorldTest extends TestBase
 {
     @Test
-    void testGlyphLayoutHelloWorldAWT() throws IOException, 
FontFormatException, URISyntaxException
+    void testGlyphLayoutHelloWorld() throws IOException, URISyntaxException
     {
         String outputName = "HelloWorld.pdf";
-        String lohitBengaliPath = "/ttf/Lohit-Bengali.ttf";
-        File file = new 
File(GlyphLayoutHelloWorldAWTTest.class.getResource(lohitBengaliPath).toURI());
-        String [] args = new String[]{ "target/" + outputName, "হ্যালো 
ওয়ার্ল্ড", file.getPath() };
-        GlyphLayoutHelloWorldAWT.main(args);
+        String lohitBengaliPath = "/ttf/DejaVuSans.ttf";
+        File file = new 
File(GlyphLayoutHelloWorldTest.class.getResource(lohitBengaliPath).toURI());
+        // Ligatures work by default for this font
+        String [] args = new String[]{ "target/" + outputName, "Effective", 
file.getPath() };
+        GlyphLayoutHelloWorldFOP.main(args);
         checkRenderIdent(outputName);
     }
 }

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutLigaturesAndKerningTest.java
 (from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutLigaturesAndKerningTest.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutLigaturesAndKerningTest.java
      Mon Jul  6 08:32:53 2026        (r1935929, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutLigaturesAndKerningTest.java
      Thu Jul 30 08:33:24 2026        (r1936716)
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
 
 /**
  * Examples for ligatures and kerning
@@ -27,7 +27,6 @@ package org.apache.pdfbox.glyphlayout.aw
  * @author Volker Kunert
  */
 
-import java.awt.FontFormatException;
 import java.io.IOException;
 import java.net.URISyntaxException;
 
@@ -45,28 +44,24 @@ class GlyphLayoutLigaturesAndKerningTest
     static final String FIRACODE_STRING = "!= == === >= <=";
     static final String DEJAVU_STRING =  "AVATAR, effective, affiliation, 
float, film, affluent";
     static final String BENGALI_STRING =  "আমি কোন পথে ক্ষীরের লক্ষ্মী ষন্ড 
পুতুল রুপো গঙ্গা ঋষি";
-    
-    // for code coverage at the end of showTextUni
-    // happens only if font size 20 and the spaces
-    static final String BENGALI_STRING2 =  "    আর সবই গেছে ঋণে।";
+    static final String THAI_STRING =  "กูกินก้งปิ้งอยู่ในถ้ำ";
+    static final String BENGALI_STRING2 =  "হ্যালো ওয়ার্ল্ড";
 
     /**
      * Check that missing glyph is caught like in main pdfbox.
      *
      * @throws IOException
-     * @throws FontFormatException 
      */
     @Test
-    void testMissingGlyph() throws IOException, FontFormatException
+    void testMissingGlyph() throws IOException
     {
-        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+        GlyphLayoutProcessorFop glyphLayoutProcessor = new 
GlyphLayoutProcessorFop();
 
         String lohitBengaliPath = "/ttf/Lohit-Bengali.ttf";
 
         try (PDDocument doc = new PDDocument())
         {
-            PDType0Font lohitBengaliFont = 
createPdType0Font(glyphLayoutProcessor, doc, lohitBengaliPath, 
-                            new GlyphLayoutFontLoaderAwt.FontOptions());
+            PDType0Font lohitBengaliFont = 
createPdType0Font(glyphLayoutProcessor, doc, lohitBengaliPath);
 
             PDPage page = new PDPage();
             doc.addPage(page);
@@ -76,7 +71,7 @@ class GlyphLayoutLigaturesAndKerningTest
 
                 IllegalArgumentException ex = 
assertThrows(IllegalArgumentException.class, () -> 
                         showComposites(cs, lohitBengaliFont, 1, 0, 0, 
"123ABC"));
-                assertEquals("Missing glyph in font 'Lohit Bengali' for the 
character 'A', codePoint: 65 (U+0041).", ex.getMessage());
+                assertEquals("Missing glyph in font 'Lohit-Bengali' for the 
character 'A', codePoint: 65 (U+0041).", ex.getMessage());
 
                 // Ignore the "You did not call endText()" warning, this is 
because of the premature close
             }
@@ -84,14 +79,15 @@ class GlyphLayoutLigaturesAndKerningTest
     }
   
     @Test
-    void testLigaturesAndKerning() throws IOException, FontFormatException, 
URISyntaxException
+    void testLigaturesAndKerning() throws IOException, URISyntaxException
     {
-        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+        GlyphLayoutProcessorFop glyphLayoutProcessor = new 
GlyphLayoutProcessorFop();
 
         String outputName = "GlyphLayoutLigaturesAndKerning.pdf";
         String outputFilename = "target/" + outputName;
         String firaPath = "/ttf/FiraCode-Regular.ttf";
         String dejavuPath = "/ttf/DejaVuSans.ttf"; // ligatures not in 
Liberation nor in Arimo
+        String thaiPath = "/ttf/NotoSansThai-Regular.ttf";
         String lohitBengaliPath = "/ttf/Lohit-Bengali.ttf";
 
         float fontSize = 12.0f;
@@ -99,22 +95,19 @@ class GlyphLayoutLigaturesAndKerningTest
         try (PDDocument doc = new PDDocument())
         {
             PDType0Font firaFont = createPdType0Font(glyphLayoutProcessor, 
doc, firaPath);
-            PDType0Font firaLigFont = createPdType0Font(glyphLayoutProcessor, 
doc, firaPath,
-                    new 
GlyphLayoutFontLoaderAwt.FontOptions().setLigaturesOn());
+            PDType0Font firaLigFont = createPdType0Font(glyphLayoutProcessor, 
doc, firaPath);
             
             PDType0Font dejavuFont = createPdType0Font(glyphLayoutProcessor, 
doc, dejavuPath);
             
-            PDType0Font dejavuLigFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath,
-                    new 
GlyphLayoutFontLoaderAwt.FontOptions().setLigaturesOn());
+            PDType0Font dejavuLigFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath);
             
-            PDType0Font dejavuKernFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath,
-                    new GlyphLayoutFontLoaderAwt.FontOptions().setKerningOn());
+            PDType0Font dejavuKernFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath);
             
-            PDType0Font dejavuLigKernFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath,
-                    new 
GlyphLayoutFontLoaderAwt.FontOptions().setLigaturesOn().setKerningOn());
-            
-            PDType0Font lohitBengaliFont = 
createPdType0Font(glyphLayoutProcessor, doc, lohitBengaliPath,
-                    new GlyphLayoutFontLoaderAwt.FontOptions());
+            PDType0Font dejavuLigKernFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath);
+
+            PDType0Font thaiFont = createPdType0Font(glyphLayoutProcessor, 
doc, thaiPath);
+
+            PDType0Font lohitBengaliFont = 
createPdType0Font(glyphLayoutProcessor, doc, lohitBengaliPath);
             
             PDPage page = new PDPage();
             doc.addPage(page);
@@ -130,8 +123,18 @@ class GlyphLayoutLigaturesAndKerningTest
                 y = showComposites(cs, dejavuLigFont, fontSize, x, y, 
DEJAVU_STRING + " (Ligatures)");
                 y = showComposites(cs, dejavuKernFont, fontSize, x, y, 
DEJAVU_STRING + " (Kerning)");
                 y = showComposites(cs, dejavuLigKernFont, fontSize, x, y, 
DEJAVU_STRING + " (Ligatures and kerning)");
-                y = showComposites(cs, lohitBengaliFont, fontSize, x, y, 
BENGALI_STRING + " (ভারত)");
-                showComposites(cs, lohitBengaliFont, 20, x, y - 20, 
BENGALI_STRING2 + " (ভারত)");
+                y = showComposites(cs, thaiFont, fontSize, x, y, THAI_STRING);
+                y = showComposites(cs, lohitBengaliFont, fontSize, x, y - 5, 
BENGALI_STRING + " (ভারত)");
+
+                // from the related awt test. Unclear if useful in the future 
if FOP ever supports bengali
+                // and we get access to it.
+                cs.beginText();
+                cs.setFont(lohitBengaliFont, 20);
+                cs.newLineAtOffset(x, y - 20);
+                cs.showText(BENGALI_STRING2);
+                cs.showText(" ");
+                cs.showText(BENGALI_STRING2);
+                cs.endText();
             }
             doc.save(outputFilename);
         }

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutSMPTest.java
 (from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutSMPTest.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/GlyphLayoutSMPTest.java
      Mon Jul  6 08:32:53 2026        (r1935929, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/GlyphLayoutSMPTest.java
      Thu Jul 30 08:33:24 2026        (r1936716)
@@ -15,9 +15,8 @@
  * limitations under the License.
  */
 
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
 
-import java.awt.FontFormatException;
 import java.io.IOException;
 import java.net.URISyntaxException;
 
@@ -28,7 +27,7 @@ import org.apache.pdfbox.pdmodel.font.PD
 import org.junit.jupiter.api.Test;
 
 /**
- * Examples for Supplementary Multilingual Plane with GlyphLayoutProcessorAwt 
that require a
+ * Examples for Supplementary Multilingual Plane with GlyphLayoutProcessorFop 
that require a
  * representation with two characters in Java. This is not a new functionality 
but a regression test
  * that needs to be checked. (Output is identical with plain PDFBox)
  *
@@ -98,9 +97,9 @@ class GlyphLayoutSMPTest extends TestBas
     }
 
     @Test
-    void testGlyphLayoutSMP() throws IOException, FontFormatException, 
URISyntaxException
+    void testGlyphLayoutSMP() throws IOException, URISyntaxException
     {
-        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+        GlyphLayoutProcessorFop glyphLayoutProcessor = new 
GlyphLayoutProcessorFop();
 
         String outputName = "GlyphLayoutSMP.pdf";
         String outputFilename = "target/" + outputName;

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/TestBase.java
 (from r1935929, 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/TestBase.java)
==============================================================================
--- 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/awt/TestBase.java
        Mon Jul  6 08:32:53 2026        (r1935929, copy source)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/java/org/apache/pdfbox/glyphlayout/fop/TestBase.java
        Thu Jul 30 08:33:24 2026        (r1936716)
@@ -14,21 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.pdfbox.glyphlayout.awt;
+package org.apache.pdfbox.glyphlayout.fop;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
 
-import java.awt.FontFormatException;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
+
 import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.font.PDType0Font;
 import org.apache.pdfbox.rendering.PDFRenderer;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
 
 /**
  *
@@ -76,24 +77,16 @@ class TestBase
     /**
      * Create the PDType0Font font
      */
-    PDType0Font createPdType0Font(GlyphLayoutProcessorAwt 
glyphLayoutProcessor, PDDocument doc,
-            String fontPath) throws IOException, FontFormatException
-    {
-        return createPdType0Font(glyphLayoutProcessor, doc, fontPath, new 
GlyphLayoutFontLoaderAwt.FontOptions());
-    }
-
-    /*
-     * Create the PDType0Font font with font options
-     */
-    PDType0Font createPdType0Font(GlyphLayoutProcessorAwt 
glyphLayoutProcessor, PDDocument doc,
-            String fontPath, GlyphLayoutFontLoaderAwt.FontOptions fontOptions) 
throws IOException, FontFormatException
+    PDType0Font createPdType0Font(GlyphLayoutProcessorFop 
glyphLayoutProcessor, PDDocument doc,
+            String fontPath) throws IOException
     {
         try (InputStream fontStream = 
this.getClass().getResourceAsStream(fontPath))
         {
-            return glyphLayoutProcessor.loadFont(doc, fontStream, fontOptions);
+            return glyphLayoutProcessor.loadFont(doc, fontStream);
         }
     }
 
+
     /*
      * show one line
      */

Copied: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/log4j2.xml (from 
r1936582, pdfbox/trunk/pdfbox-layout-awt/src/test/resources/log4j2.xml)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ pdfbox/trunk/pdfbox-layout-fop/src/test/resources/log4j2.xml        Thu Jul 
30 08:33:24 2026        (r1936716, copy of r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/log4j2.xml)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ! Licensed to the Apache Software Foundation (ASF) under one or more
+ ! contributor license agreements.  See the NOTICE file distributed with
+ ! this work for additional information regarding copyright ownership.
+ ! The ASF licenses this file to You under the Apache License, Version 2.0
+ ! (the "License"); you may not use this file except in compliance with
+ ! the License.  You may obtain a copy of the License at
+ !
+ !      http://www.apache.org/licenses/LICENSE-2.0
+ !
+ ! Unless required by applicable law or agreed to in writing, software
+ ! distributed under the License is distributed on an "AS IS" BASIS,
+ ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ! See the License for the specific language governing permissions and
+ ! limitations under the License.
+ !-->
+
+<!-- https://logging.apache.org/log4j/2.x/manual/configuration.html 
+     https://logging.apache.org/log4j/2.x/manual/appenders.html
+-->
+<Configuration>
+    <Appenders>
+        <Console name="STDOUT" target="SYSTEM_OUT">
+            <PatternLayout pattern="%d{dd.MM.yyyy HH:mm:ss} %-5p %C{2}:%L - 
%m%n"/>
+        </Console>
+        <RollingFile name="FILE" fileName="target/pdfbox.log" 
filePattern="target/pdfbox-%i.log">
+            <PatternLayout pattern="%d{dd.MM.yyyy HH:mm:ss} %-5p %C{2}:%L - 
%m%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy />
+                <SizeBasedTriggeringPolicy size="20 MB" />
+            </Policies>
+            <DefaultRolloverStrategy max="5"/>
+        </RollingFile>
+    </Appenders>
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="STDOUT"/>
+            <AppenderRef ref="FILE"/>
+        </Root>
+    </Loggers>
+</Configuration>

Added: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutBidi.pdf
==============================================================================
Binary file. No diff available.

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutDIN91379.pdf
==============================================================================
Binary file. No diff available.

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutDIN91379Form.pdf
==============================================================================
Binary file. No diff available.

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutLigaturesAndKerning.pdf
==============================================================================
Binary file. No diff available.

Added: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/GlyphLayoutSMP.pdf
==============================================================================
Binary file. No diff available.

Copied and modified: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/HelloWorld.pdf (from 
r1936582, pdfbox/trunk/pdfbox-layout-awt/src/test/resources/pdf/HelloWorld.pdf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/pdf/PdfForm.pdf (from 
r1936582, pdfbox/trunk/pdfbox-layout-awt/src/test/resources/pdf/PdfForm.pdf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/Arimo-Regular.ttf 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/Arimo-Regular.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/DejaVuSans.ttf 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/DejaVuSans.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/FiraCode-Regular.ttf 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/FiraCode-Regular.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/Lohit-Bengali.ttf 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/Lohit-Bengali.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansArabic-Regular.ttf
 (from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansArabic-Regular.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Added: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansBengali-Regular.ttf
==============================================================================
Binary file. No diff available.

Copied: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansMath-Regular.ttf 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansMath-Regular.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/ttf/NotoSansThai-Regular.ttf 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansThai-Regular.ttf)
==============================================================================
Binary file (source and/or target). No diff available.

Copied: 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/txt/GlyphLayoutDIN91379.txt 
(from r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/txt/GlyphLayoutDIN91379.txt)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-fop/src/test/resources/txt/GlyphLayoutDIN91379.txt   
    Thu Jul 30 08:33:24 2026        (r1936716, copy of r1936582, 
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/txt/GlyphLayoutDIN91379.txt)
@@ -0,0 +1,41 @@
+DIN 91379: Characters in Unicode for the electronic processing of names 
+and data exchange in Europe
+Font used: Arimo-Regular.ttf
+bll; Latin Letters (normative)
+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 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
+À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç 
è é ê ë ì í î ï ð ñ ò ó
+ô õ ö ø ù ú û ü ý þ ÿ Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě 
Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ ĥ Ħ
+ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō 
Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş
+ş Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž Ƈ ƈ Ə Ɨ Ơ ơ Ư 
ư Ʒ Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ
+Ǘ ǘ Ǚ ǚ Ǜ ǜ Ǟ ǟ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ Ǵ ǵ Ǹ ǹ Ǻ ǻ Ǽ ǽ Ǿ ǿ Ȓ ȓ Ș ș Ț ț 
Ȟ ȟ ȧ Ȩ ȩ Ȫ ȫ Ȭ ȭ
+Ȯ ȯ Ȱ ȱ Ȳ ȳ ə ɨ ʒ Ḃ ḃ Ḇ ḇ Ḋ ḋ Ḍ ḍ Ḏ ḏ Ḑ ḑ ḗ Ḝ ḝ Ḟ ḟ Ḡ ḡ Ḣ ḣ Ḥ ḥ Ḧ ḧ Ḩ ḩ Ḫ ḫ ḯ 
Ḱ ḱ Ḳ ḳ Ḵ ḵ Ḷ ḷ Ḻ ḻ Ṁ
+ṁ Ṃ ṃ Ṅ ṅ Ṇ ṇ Ṉ ṉ Ṓ ṓ Ṕ ṕ Ṗ ṗ Ṙ ṙ Ṛ ṛ Ṟ ṟ Ṡ ṡ Ṣ ṣ Ṫ ṫ Ṭ ṭ Ṯ ṯ Ẁ ẁ Ẃ ẃ Ẅ ẅ Ẇ ẇ 
Ẍ ẍ Ẏ ẏ Ẑ ẑ Ẓ ẓ Ẕ ẕ
+ẖ ẗ ẞ Ạ ạ Ả ả Ấ ấ Ầ ầ Ẩ ẩ Ẫ ẫ Ậ ậ Ắ ắ Ằ ằ Ẳ ẳ Ẵ ẵ Ặ ặ Ẹ ẹ Ẻ ẻ Ẽ ẽ Ế ế Ề ề Ể ể 
Ễ ễ Ệ ệ Ỉ ỉ Ị ị Ọ ọ Ỏ ỏ Ố
+ố Ồ ồ Ổ ổ Ỗ ỗ Ộ ộ Ớ ớ Ờ ờ Ở ở Ỡ ỡ Ợ ợ Ụ ụ Ủ ủ Ứ ứ Ừ ừ Ử ử Ữ ữ Ự ự Ỳ ỳ Ỵ ỵ Ỷ ỷ 
Ỹ ỹ
+Sequences
+A̋ C̀ C̄ C̆ C̈ C̕ C̣ C̦ C̨̆ D̂ F̀ F̄ G̀ H̄ H̦ H̱ J́ J̌ K̀ K̂ K̄ K̇ K̕ K̛ K̦ 
K͟H 
+K͟h L̂ L̥ L̥̄ L̦ M̀ M̂ M̆ M̐ N̂ N̄ N̆ N̦ P̀ P̄ P̕ P̣ R̆ R̥ R̥̄ S̀ S̄ S̛̄ S̱ T̀ 
T̄ 
+T̈ T ̕T̛ U̇ Z̀ Z̄ Z̆ Z̈ Z̧ a̋ c̀ c̄ c̆ c̈ c̕ c ̣c̦ c̨̆ d̂ f ̀f̄ g̀ h̄ h̦ ȷ ́k̀ 
+k̂ k̄ k̇ k ̕k̛ k̦ k͟h l̂ l̥ l̥̄ l̦ m̀ m̂ m̆ m̐ n̂ n̄ n̆ n̦ p̀ p̄ p̕ p ̣r̆ r̥ 
r̥̄ 
+s̀ s̄ s̛̄ s̱ t̀ t̄ t̕ t̛ u̇ z̀ z̄ z̆ z̈ z̧ Ç̆ Û̄ ç̆ û̄ ÿ́ Č̕ Č̣ č ̕č ̣ē̍ Ī́ ī́ 
+ō̍ Ž̦ Ž̧ ž̦ ž̧ Ḳ̄ ḳ̄ Ṣ̄ ṣ̄ Ṭ̄ ṭ̄ Ạ̈ ạ̈ Ọ̈ ọ̈ Ụ̄ Ụ̈ ụ̄ ụ̈ 
+bnlreq; Non-Letters N1 (normative)
+  ' , - . ` ~ ¨ ´ · ʹ ʺ ʾ ʿ ˈ ˌ ’ ‡ 
+bnl; Non-Letters N2 (normative)
+! " # $ % & ( ) * + / 0 1 2 3 4 5 6 7 8 9 : ; < = > 
+? @ [ \ ] ^ _ { | } ¡ ¢ £ ¥ § © ª « ¬ ® ¯ ° ± ² ³ µ 
+¶ ¹ º » ¿ × ÷ € 
+bnlopt; Non-Letters N3 (normative)
+¤ ¦ ¸ ¼ ½ ¾ 
+gl; Greek Letters (extended)
+Ά Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ 
+Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν 
+ξ ο π ρ ς σ τ υ φ χ ψ ω ϊ ϋ ό ύ ώ 
+cl; Cyrillic Letters (extended)
+Ѝ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш 
+Щ Ъ Ь Ю Я а б в г д е ж з и й к л м н о п р с т у ф 
+х ц ч ш щ ъ ь ю я ѝ 
+enl; Non-Letters E1 (extended)
+ƒ ʰ ʳ ˆ ˜ ˢ ᵈ ᵗ ‘ ‚ “ ” „ † … ‰ ′ ″ ‹ › ⁰ ⁴ ⁵ ⁶ ⁷ ⁸ 
+⁹ ⁿ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ™ ∞ ≤ ≥ 
+Additional non-letters (not included in DIN 91379): – — •�

Modified: pdfbox/trunk/pom.xml
==============================================================================
--- pdfbox/trunk/pom.xml        Thu Jul 30 08:30:47 2026        (r1936715)
+++ pdfbox/trunk/pom.xml        Thu Jul 30 08:33:24 2026        (r1936716)
@@ -37,6 +37,7 @@
     <module>xmpbox</module>
     <module>pdfbox</module>
     <module>pdfbox-layout-awt</module>
+    <module>pdfbox-layout-fop</module>
     <module>debugger</module>
     <module>tools</module>
     <module>app</module>

Reply via email to