From 76740bd2a49d2574383edafacf4c86c963276044 Mon Sep 17 00:00:00 2001
From: linyuxuan <linyuxuan@kylinos.cn>
Date: Fri, 5 Jan 2024 10:36:13 +0800
Subject: [PATCH 3/4] Implements the FONTCONFIGURATION_FALLBACK on Linux

Uses FcFontConfiguration to build a fallback composite font.
Gets the information for the fallback font from fontconfig.
---
 .../unix/classes/sun/awt/FcFontManager.java   | 41 +++++++++++++++-
 .../classes/sun/font/FcFontConfiguration.java | 36 +++++++++++++-
 .../classes/sun/font/FontConfigManager.java   | 49 ++++++++++++++++---
 3 files changed, 116 insertions(+), 10 deletions(-)

diff --git a/src/java.desktop/unix/classes/sun/awt/FcFontManager.java b/src/java.desktop/unix/classes/sun/awt/FcFontManager.java
index ecd7ac0ad35..1457252ee22 100644
--- a/src/java.desktop/unix/classes/sun/awt/FcFontManager.java
+++ b/src/java.desktop/unix/classes/sun/awt/FcFontManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,12 @@
 
 package sun.awt;
 
+import sun.font.CompositeFont;
+import sun.font.CompositeFontDescriptor;
 import sun.font.FcFontConfiguration;
+import sun.font.Font2D;
 import sun.font.FontConfigManager;
+import sun.font.FontUtilities;
 import sun.font.SunFontManager;
 
 /**
@@ -67,6 +71,41 @@ public FontConfiguration createFontConfiguration(boolean preferLocaleFonts,
         }
     }
 
+    @Override
+    public Font2D getFontFromFontConfiguration(String name, int style) {
+        CompositeFont cf = createCompositeFont(name, style);
+        if (cf == null) {
+            if (FontUtilities.debugFonts()) {
+                FontUtilities.logWarning("can't get font from fontconfiguration.");
+            }
+            return super.getDefaultLogicalFont(style);
+        }
+        return cf;
+    }
+
+    /**
+     * Builds a composite font using the information from fontconfig
+     */
+    protected CompositeFont createCompositeFont(String name, int style) {
+        FcFontConfiguration fcFontConfig = (FcFontConfiguration)createFontConfiguration();
+        CompositeFontDescriptor fontInfo = fcFontConfig.get2DCompositeFontInfo(name, style);
+        if (fontInfo == null) {
+            return null;
+        }
+
+        String[] componentFileNames = fontInfo.getComponentFileNames();
+        String[] componentFaceNames = fontInfo.getComponentFaceNames();
+
+        CompositeFont cf = new CompositeFont(fontInfo.getFaceName(),
+                                             componentFileNames,
+                                             componentFaceNames,
+                                             fontInfo.getCoreComponentCount(),
+                                             fontInfo.getExclusionRanges(),
+                                             fontInfo.getExclusionRangeLimits(),
+                                             true, this);
+        return cf;
+    }
+
     @Override
     protected String[] getDefaultPlatformFont() {
         final String[] info = new String[2];
diff --git a/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java b/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java
index 8638bd3f594..4233b0ce98c 100644
--- a/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java
+++ b/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -231,6 +231,40 @@ private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
         return fcFonts[0].allFonts;
     }
 
+    /**
+     * Gets the information for the specified font from Fontconfig
+     */
+    public CompositeFontDescriptor get2DCompositeFontInfo(String name, int style) {
+        FcFontManager fm = (FcFontManager) fontManager;
+        FontConfigManager fcm = fm.getFontConfigManager();
+        FcCompFont fcCompFont = fcm.getFontConfigMatch(name, style, true);
+        if (fcCompFont == null) {
+            return null;
+        }
+
+        String faceName = name + "." + styleNames[style];
+        FontConfigFont[] fcFonts = fcCompFont.allFonts;
+
+        int numFonts = fcFonts.length;
+        String[] fileNames = new String[numFonts];
+        String[] faceNames = new String[numFonts];
+
+        int index;
+        for (index = 0; index < fcFonts.length; index++) {
+            faceNames[index] = fcFonts[index].fullName;
+            fileNames[index] = fcFonts[index].fontFile;
+        }
+
+        CompositeFontDescriptor result
+                = new CompositeFontDescriptor(
+                    faceName,
+                    1,
+                    faceNames,
+                    fileNames,
+                    null, null);
+        return result;
+    }
+
     @Override
     public CompositeFontDescriptor[] get2DCompositeFontInfo() {
 
diff --git a/src/java.desktop/unix/classes/sun/font/FontConfigManager.java b/src/java.desktop/unix/classes/sun/font/FontConfigManager.java
index 6e3b83f4b66..627b7fb3e55 100644
--- a/src/java.desktop/unix/classes/sun/font/FontConfigManager.java
+++ b/src/java.desktop/unix/classes/sun/font/FontConfigManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -96,6 +96,13 @@ public static class FontConfigInfo {
         "monospace:bold:italic",
     };
 
+    private static String[] fontConfigStyles = {
+        "regular:roman",
+        "bold:roman",
+        "regular:italic",
+        "bold:italic"
+    };
+
     /* This array has the array elements created in Java code and is
      * passed down to native to be filled in.
      */
@@ -188,7 +195,8 @@ public synchronized void initFontConfigFonts(boolean includeFallbacks) {
             fontArr[i].jdkName = FontUtilities.mapFcName(fontArr[i].fcFamily);
             fontArr[i].style = i % 4; // depends on array order.
         }
-        getFontConfig(getFCLocaleStr(), fcInfo, fontArr, includeFallbacks);
+        getFontConfigInfo(fcInfo);
+        getFontConfigMatch(getFCLocaleStr(), fontArr, includeFallbacks);
         FontConfigFont anyFont = null;
         /* If don't find anything (eg no libfontconfig), then just return */
         for (int i = 0; i< fontArr.length; i++) {
@@ -432,13 +440,10 @@ public FcCompFont[] getFontConfigFonts() {
         return fontConfigFonts;
     }
 
-    /* Return an array of FcCompFont structs describing the primary
-     * font located for each of fontconfig/GTK/Pango's logical font names.
+    /* Return a FontConfigInfo struct describing the version
+     * and cache directory information for fontconfig
      */
-    private static native void getFontConfig(String locale,
-                                             FontConfigInfo fcInfo,
-                                             FcCompFont[] fonts,
-                                             boolean includeFallbacks);
+    private static native void getFontConfigInfo(FontConfigInfo fcInfo);
 
     void populateFontConfig(FcCompFont[] fcInfo) {
         fontConfigFonts = fcInfo;
@@ -454,6 +459,34 @@ FontConfigInfo getFontConfigInfo() {
         return fcInfo;
     }
 
+    /* Return an array of FcCompFont structs describing the primary
+     * font located for each of fontconfig/GTK/Pango's logical font names.
+     */
+    private static native void
+    getFontConfigMatch(String locale, FcCompFont[] fonts, boolean includeFallbacks);
+
+    FcCompFont getFontConfigMatch(String name, int style, boolean includeFallbacks) {
+        if (FontUtilities.isWindows || fontConfigFailed) {
+            return null;
+        }
+
+        FcCompFont[] fontArr = new FcCompFont[1];
+        fontArr[0] = new FcCompFont();
+
+        fontArr[0].fcName = name + ":" + fontConfigStyles[style];
+
+        getFontConfigMatch(getFCLocaleStr(), fontArr, includeFallbacks);
+
+        if (fontArr[0].firstFont == null) {
+            if (FontUtilities.isLogging()) {
+                FontUtilities.logInfo("Fontconfig returned no font for " + fontArr[0].fcName);
+            }
+            fontConfigFailed = true;
+            return null;
+        }
+        return fontArr[0];
+    }
+
     private static native int
     getFontConfigAASettings(String locale, String fcFamily);
 }
-- 
2.39.2

