Author: tilman
Date: Sat Jul  4 13:31:20 2026
New Revision: 1935881

Log:
PDFBOX-4951: add tests, by Volker Kunert; move resources to test for now

Added:
   pdfbox/trunk/pdfbox-layout-awt/src/test/appended-resources/
   pdfbox/trunk/pdfbox-layout-awt/src/test/appended-resources/META-INF/
   pdfbox/trunk/pdfbox-layout-awt/src/test/appended-resources/META-INF/LICENSE  
 (contents, props changed)
   pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/
   pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/
   pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/
   pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/
   
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutBidiTest.java
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutDin91379FormTest.java
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutDin91379Test.java
   (contents, props changed)
   
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutLigaturesAndKerningTest.java
   (contents, props changed)
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/pdf/
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/pdf/PdfForm.pdf   
(contents, props changed)
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/DejaVuSans.ttf   
(contents, props changed)
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/FiraCode-Regular.ttf   
(contents, props changed)
   pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/Lohit-Bengali.ttf   
(contents, props changed)
   
pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/NotoSansArabic-Regular.ttf
   (contents, props changed)

Added: 
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-awt/src/test/appended-resources/META-INF/LICENSE 
Sat Jul  4 13:31:20 2026        (r1935881)
@@ -0,0 +1,278 @@
+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
+
+
+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

Added: 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutBidiTest.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutBidiTest.java
 Sat Jul  4 13:31:20 2026        (r1935881)
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import org.junit.jupiter.api.Test;
+
+import java.awt.FontFormatException;
+import java.io.IOException;
+import java.io.InputStream;
+
+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;
+
+/**
+ * Examples for bidirectional text with GlyphLayoutProcessorAwt
+ *
+ * @author Volker Kunert
+ */
+public class GlyphLayoutBidiTest
+{
+    public static final String TEXT1 = "نحن الآن في شهر رمضان 1447 هجري";
+    public static final String TEXT2 = "Guten Tag ";
+    public static final String TEXT3 = "السلام عليكم";
+    public static final String TEXT4 = " Good afternoon";
+
+    /*
+     * show one line
+     */
+    private float showLine(PDPageContentStream cs, PDType0Font font, float 
fontSize,
+            float x, float y, String text) throws IOException
+    {
+        return showLine(cs, new PDType0Font[]{font}, fontSize, x, y, new 
String[]{text});
+    }
+
+    /*
+     * show one line
+     */
+    private float showLine(PDPageContentStream cs, PDType0Font[] fonts, float 
fontSize,
+            float x, float y, String[] texts) throws IOException
+    {
+        cs.beginText();
+        cs.newLineAtOffset(x, y);
+
+        if (fonts.length != texts.length)
+        {
+            throw new IllegalArgumentException("Size of fonts and texts is 
different");
+        }
+        for (int i = 0; i < texts.length; i++)
+        {
+            cs.setFont(fonts[i], fontSize);
+            cs.showText(texts[i]);
+        }
+        cs.endText();
+
+        float height = fonts[0].getBoundingBox().getHeight();
+        y -= height / 1000f * fontSize;
+        return y;
+    }
+
+    @Test
+    void testGlyphLayoutBidi() throws IOException, FontFormatException
+    {
+        GlyphLayoutProcessorAwt glyphLayoutProcessorAwt = new 
GlyphLayoutProcessorAwt();
+
+        String outputFilename = "target/GlyphLayoutBidi.pdf";
+        String arabicPath = "/ttf/NotoSansArabic-Regular.ttf";
+        String lgcPath = "/ttf/DejaVuSans.ttf";
+
+        float fontSize = 12.0f;
+
+        try (PDDocument doc = new PDDocument())
+        {
+            PDType0Font arabicFont = 
createPdType0Font(glyphLayoutProcessorAwt, doc, arabicPath);
+            PDType0Font lgcFont = createPdType0Font(glyphLayoutProcessorAwt, 
doc, lgcPath);
+
+            PDPage page = new PDPage();
+            doc.addPage(page);
+            try (PDPageContentStream cs = new PDPageContentStream(doc, page))
+            {
+                cs.setGlyphLayoutProcessor(glyphLayoutProcessorAwt);
+                
+                float x = page.getBBox().getLowerLeftX() + fontSize;
+                float y = page.getBBox().getUpperRightY() - fontSize;
+                
+                y = showLine(cs, arabicFont, fontSize, x, y, TEXT1);
+                showLine(cs, new PDType0Font[]{ lgcFont, arabicFont, lgcFont 
}, fontSize, x, y, new String[]{ TEXT2, TEXT3, TEXT4 });
+            }
+            doc.save(outputFilename);
+        }
+    }
+
+    /*
+     * Create the PDType0Font font
+     */
+    private PDType0Font createPdType0Font(GlyphLayoutProcessorAwt 
glyphLayoutProcessorAwt, PDDocument doc,
+            String fontPath) throws IOException, FontFormatException
+    {
+        InputStream fontStream = this.getClass().getResourceAsStream(fontPath);
+        return glyphLayoutProcessorAwt.loadFont(doc, fontStream);
+    }
+}

Added: 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutDin91379FormTest.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutDin91379FormTest.java
 Sat Jul  4 13:31:20 2026        (r1935881)
@@ -0,0 +1,136 @@
+/*
+ * 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;
+
+import java.awt.FontFormatException;
+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.PDDocumentCatalog;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
+
+/*
+ * Example of formatting for letters defined in:
+ * DIN 91379: Characters and defined character sequences in Unicode for the 
electronic processing of names
+ * and data exchange in Europe
+ * <p>
+ * Use of the glyph layout features of Java that are based on HarfBuzz
+ *
+ * @author Volker Kunert
+ * @date 2026-04-04
+ */
+
+public class GlyphLayoutDin91379FormTest
+{
+    static String LATIN_CHARS_DIN_91379 =
+                    "DIN 91379: Characters in Unicode for the electronic 
processing of names "
+                    + "and data exchange in Europe\n"
+                    + "bll; Latin Letters (normative)\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 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 Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş "
+                    + "ş Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź 
Ż ż Ž ž Ƈ ƈ Ə Ɨ Ơ ơ Ư ư Ʒ Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ "
+                    + "Ǘ ǘ Ǚ ǚ Ǜ ǜ Ǟ ǟ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ Ǵ ǵ Ǹ ǹ Ǻ 
ǻ Ǽ ǽ Ǿ ǿ Ȓ ȓ Ș ș Ț ț Ȟ ȟ ȧ Ȩ ȩ Ȫ ȫ Ȭ ȭ "
+                    + "Ȯ ȯ Ȱ ȱ Ȳ ȳ ə ɨ ʒ Ḃ ḃ Ḇ ḇ Ḋ ḋ Ḍ ḍ Ḏ ḏ Ḑ ḑ ḗ Ḝ ḝ Ḟ ḟ Ḡ ḡ 
Ḣ ḣ Ḥ ḥ Ḧ ḧ Ḩ ḩ Ḫ ḫ ḯ Ḱ ḱ Ḳ ḳ Ḵ ḵ Ḷ ḷ Ḻ ḻ Ṁ "
+                    + "ṁ Ṃ ṃ Ṅ ṅ Ṇ ṇ Ṉ ṉ Ṓ ṓ Ṕ ṕ Ṗ ṗ Ṙ ṙ Ṛ ṛ Ṟ ṟ Ṡ ṡ Ṣ ṣ Ṫ ṫ Ṭ 
ṭ Ṯ ṯ Ẁ ẁ Ẃ ẃ Ẅ ẅ Ẇ ẇ Ẍ ẍ Ẏ ẏ Ẑ ẑ Ẓ ẓ Ẕ ẕ "
+                    + "ẖ ẗ ẞ Ạ ạ Ả ả Ấ ấ Ầ ầ Ẩ ẩ Ẫ ẫ Ậ ậ Ắ ắ Ằ ằ Ẳ ẳ Ẵ ẵ Ặ ặ Ẹ 
ẹ Ẻ ẻ Ẽ ẽ Ế ế Ề ề Ể ể Ễ ễ Ệ ệ Ỉ ỉ Ị ị Ọ ọ Ỏ ỏ Ố "
+                    + "ố Ồ ồ Ổ ổ Ỗ ỗ Ộ ộ Ớ ớ Ờ ờ Ở ở Ỡ ỡ Ợ ợ Ụ ụ Ủ ủ Ứ ứ Ừ ừ Ử 
ử Ữ ữ Ự ự Ỳ ỳ Ỵ ỵ Ỷ ỷ Ỹ ỹ\n"
+                    + "Sequences\n"
+                    + "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̦ j́ 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̧ Ç̆ Û̄ ç̆ û̄ 
ÿ́ Č̕ Č̣ č̕ č̣ ē̍ Ī́ ī́ "
+                    + "ō̍ Ž̦ Ž̧ ž̦ ž̧ Ḳ̄ ḳ̄ Ṣ̄ ṣ̄ Ṭ̄ ṭ̄ Ạ̈ ạ̈ Ọ̈ ọ̈ Ụ̄ Ụ̈ ụ̄ 
ụ̈\n"
+                    + "bnlreq; Non-Letters N1 (normative)\n"
+                    + "  ' , - . ` ~ ¨ ´ · ʹ ʺ ʾ ʿ ˈ ˌ ’ ‡\n"
+                    + "bnl; Non-Letters N2 (normative)\n"
+                    + "! \" # $ % & ( ) * + / 0 1 2 3 4 5 6 7 8 9 : ; < = > "
+                    + "? @ [ \\ ] ^ _ { | } ¡ ¢ £ ¥ § © ª « ¬ ® ¯ ° ± ² ³ µ "
+                    + "¶ ¹ º » ¿ × ÷ € \n"
+                    + "bnlopt; Non-Letters N3 (normative)\n"
+                    + "¤ ¦ ¸ ¼ ½ ¾ \n"
+                    + "gl; Greek Letters (extended)\n"
+                    + "Ά Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ "
+                    + "Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν "
+                    + "ξ ο π ρ ς σ τ υ φ χ ψ ω ϊ ϋ ό ύ ώ \n"
+                    + "cl; Cyrillic Letters (extended)\n"
+                    + "Ѝ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш "
+                    + "Щ Ъ Ь Ю Я а б в г д е ж з и й к л м н о п р с т у ф "
+                    + "х ц ч ш щ ъ ь ю я ѝ \n"
+                    + "enl; Non-Letters E1 (extended)\n"
+                    + "ƒ ʰ ʳ ˆ ˜ ˢ ᵈ ᵗ ‘ ‚ “ ” „ † … ‰ ′ ″ ‹ › ⁰ ⁴ ⁵ ⁶ ⁷ ⁸ "
+                    + "⁹ ⁿ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ™ ∞ ≤ ≥ \n"
+                    + "Additional non-letters (not included in DIN 91379): – — 
•�";
+
+    @Test
+    void testGlyphLayoutDin91379Form() throws IOException, 
FontFormatException, URISyntaxException
+    {
+        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+
+        String outputFilename = "target/GlyphLayoutDIN91379Form.pdf";
+
+        String fontSizeString = "10.5";
+
+        InputStream fontStream = 
GlyphLayoutDin91379FormTest.class.getResourceAsStream("/ttf/DejaVuSans.ttf");
+        File pdfForm = new 
File(GlyphLayoutDin91379FormTest.class.getResource("/pdf/PdfForm.pdf").toURI());
+
+        try (PDDocument doc = Loader.loadPDF(pdfForm))
+        {
+            // embedSubset has to be set to false
+            PDType0Font font = glyphLayoutProcessor.loadFont(doc, fontStream, 
false);
+
+            PDDocumentCatalog docCatalog = doc.getDocumentCatalog();
+            PDAcroForm acroForm = docCatalog.getAcroForm();
+
+            acroForm.setGlyphLayoutProcessor(glyphLayoutProcessor);
+
+            PDResources resources = new PDResources();
+            String resourceFontName = resources.add(font).getName();
+            acroForm.setDefaultResources(resources);
+            for (PDField field : acroForm.getFields())
+            {
+                if (field instanceof PDTextField)
+                {
+                    PDTextField textfield = (PDTextField) field;
+                    textfield.setDefaultAppearance(
+                            String.format("/%s %s Tf 0 g ", resourceFontName, 
fontSizeString));
+                    textfield.setValue(LATIN_CHARS_DIN_91379);
+                }
+            }
+            acroForm.refreshAppearances();
+            acroForm.flatten();
+            doc.save(outputFilename);
+        }
+
+        //TODO add rendering comparison
+        try (PDDocument doc = Loader.loadPDF(new File(outputFilename)))
+        {
+            assertEquals(1, doc.getNumberOfPages());
+        }
+    }
+}

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

Added: 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutLigaturesAndKerningTest.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
pdfbox/trunk/pdfbox-layout-awt/src/test/java/org/apache/pdfbox/glyphlayout/GlyphLayoutLigaturesAndKerningTest.java
  Sat Jul  4 13:31:20 2026        (r1935881)
@@ -0,0 +1,190 @@
+/*
+ * 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;
+
+/**
+ * Examples for ligatures and kerning
+ * See <a 
href="https://issues.apache.org/jira/browse/PDFBOX-4951";>PDFBOX-4951</a>
+ *
+ * The default processing of GlyphLayoutProcessor is with ligatures and 
kerning disabled.
+ * You can enable ligatures and kerning using FontOptions, see below.
+ *
+ * @author Volker Kunert
+ */
+
+import java.awt.FontFormatException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.Test;
+
+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;
+
+public class GlyphLayoutLigaturesAndKerningTest
+{
+    static final String FIRACODE_STRING = "!= == === >= <=";
+    static final String DEJAVU_STRING =  "AVATAR, effective, affiliation, 
float, film, affluent";
+    static final String BENGALI_STRING =  "আমি কোন পথে ক্ষীরের লক্ষ্মী ষন্ড 
পুতুল রুপো গঙ্গা ঋষি";
+    
+    /**
+     * Check that missing glyph is caught like in main pdfbox.
+     *
+     * @throws IOException
+     * @throws FontFormatException 
+     */
+    @Test
+    void testMissingGlyph() throws IOException, FontFormatException
+    {
+        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+
+        String lohitBengaliPath = "/ttf/Lohit-Bengali.ttf";
+
+        try (PDDocument doc = new PDDocument())
+        {
+            PDType0Font lohitBengaliFont = 
createPdType0Font(glyphLayoutProcessor, doc, lohitBengaliPath);
+
+            PDPage page = new PDPage();
+            doc.addPage(page);
+            try (PDPageContentStream cs = new PDPageContentStream(doc, page))
+            {
+                cs.setGlyphLayoutProcessor(glyphLayoutProcessor);
+                
+                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());
+            }
+        }
+    }
+  
+    @Test
+    void testLigaturesAndKerning() throws IOException, FontFormatException
+    {
+        GlyphLayoutProcessorAwt glyphLayoutProcessor = new 
GlyphLayoutProcessorAwt();
+
+        String outputFilename = "target/GlyphLayoutLigaturesAndKerning.pdf";
+        String firaPath = "/ttf/FiraCode-Regular.ttf";
+        String dejavuPath = "/ttf/DejaVuSans.ttf"; // ligatures not in 
Liberation nor in Arimo
+        String lohitBengaliPath = "/ttf/Lohit-Bengali.ttf";
+
+        float fontSize = 12.0f;
+
+        try (PDDocument doc = new PDDocument())
+        {
+            PDType0Font firaFont = createPdType0Font(glyphLayoutProcessor, 
doc, firaPath);
+            PDType0Font firaLigFont = createPdType0Font(glyphLayoutProcessor, 
doc, firaPath,
+                    new 
GlyphLayoutFontLoaderAwt.FontOptions().setLigaturesOn());
+            
+            PDType0Font dejavuFont = createPdType0Font(glyphLayoutProcessor, 
doc, dejavuPath);
+            
+            PDType0Font dejavuLigFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath,
+                    new 
GlyphLayoutFontLoaderAwt.FontOptions().setLigaturesOn());
+            
+            PDType0Font dejavuKernFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath,
+                    new GlyphLayoutFontLoaderAwt.FontOptions().setKerningOn());
+            
+            PDType0Font dejavuLigKernFont = 
createPdType0Font(glyphLayoutProcessor, doc, dejavuPath,
+                    new 
GlyphLayoutFontLoaderAwt.FontOptions().setLigaturesOn().setKerningOn());
+            
+            PDType0Font lohitBengaliFont = 
createPdType0Font(glyphLayoutProcessor, doc, lohitBengaliPath,
+                    new GlyphLayoutFontLoaderAwt.FontOptions());
+            
+            PDPage page = new PDPage();
+            doc.addPage(page);
+            try (PDPageContentStream cs = new PDPageContentStream(doc, page))
+            {
+                cs.setGlyphLayoutProcessor(glyphLayoutProcessor);
+                
+                float x = page.getBBox().getLowerLeftX() + fontSize;
+                float y = page.getBBox().getUpperRightY() - fontSize;
+                y = showComposites(cs, firaFont, fontSize, x, y, 
FIRACODE_STRING);
+                y = showComposites(cs, firaLigFont, fontSize, x, y, 
FIRACODE_STRING + " (Ligatures)");
+                y = showComposites(cs, dejavuFont, fontSize, x, y, 
DEJAVU_STRING);
+                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)");
+                showComposites(cs, lohitBengaliFont, fontSize, x, y, 
BENGALI_STRING + " (ভারত)");
+            }
+            doc.save(outputFilename);
+        }
+    }
+
+    /*
+     * Create the PDType0Font font
+     */
+    private PDType0Font createPdType0Font(GlyphLayoutProcessorAwt 
glyphLayoutProcessor, PDDocument pdDocument,
+            String fontPath) throws IOException, FontFormatException
+    {
+        InputStream fontStream = this.getClass().
+                getResourceAsStream(fontPath);
+        PDType0Font font = glyphLayoutProcessor.loadFont(pdDocument, 
fontStream);
+        return font;
+    }
+
+    /*
+     * Create the PDType0Font font with font options
+     */
+    private PDType0Font createPdType0Font(GlyphLayoutProcessorAwt 
glyphLayoutProcessor, PDDocument pdDocument,
+            String fontPath, GlyphLayoutFontLoaderAwt.FontOptions fontOptions) 
throws IOException, FontFormatException
+    {
+        InputStream fontStream = this.getClass().
+                getResourceAsStream(fontPath);
+        PDType0Font font = glyphLayoutProcessor.loadFont(pdDocument, 
fontStream, fontOptions);
+        return font;
+    }
+
+    /*
+     * break the text into lines and show them
+     */
+    public static float showComposites(PDPageContentStream cs, PDType0Font 
font, float fontSize,
+            float x, float y, String s) throws IOException
+    {
+
+        s = s.replaceAll("\t", "    ");
+        String[] lines = s.split("[\n]");
+
+        float height = font.getBoundingBox().getHeight();
+
+        for (String line : lines)
+        {
+            if (!line.isEmpty())
+            {
+                showCompositesLine(cs, font, fontSize, x, y, line);
+                y -= height / 1000f * fontSize;
+            }
+        }
+        return y;
+    }
+
+    /*
+     * show one line
+     */
+    public static void showCompositesLine(PDPageContentStream cs, PDType0Font 
font, float fontSize,
+            float x, float y, String line) throws IOException
+    {
+        cs.beginText();
+        cs.setFont(font, fontSize);
+        cs.newLineAtOffset(x, y);
+        cs.showText(line);
+        cs.endText();
+    }
+}

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

Added: pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/DejaVuSans.ttf
==============================================================================
Binary file. No diff available.

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

Added: pdfbox/trunk/pdfbox-layout-awt/src/test/resources/ttf/Lohit-Bengali.ttf
==============================================================================
Binary file. No diff available.

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


Reply via email to