Skip to content

Commit

Permalink
Merge PR #545: Fonts (Inter and JetBrains Mono)
Browse files Browse the repository at this point in the history
  • Loading branch information
DevCharly committed Nov 18, 2022
2 parents ccca6fe + 0d2e1e6 commit 24bc7fb
Show file tree
Hide file tree
Showing 41 changed files with 1,191 additions and 49 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Expand Up @@ -20,7 +20,9 @@
*.gif binary
*.jar binary
*.lib binary
*.otf binary
*.png binary
*.sketch binary
*.so binary
*.ttf binary
*.zip binary
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Expand Up @@ -54,6 +54,7 @@ jobs:
name: FlatLaf-build-artifacts
path: |
flatlaf-*/build/libs
flatlaf-*/flatlaf-*/build/libs
!**/*-javadoc.jar
!**/*-sources.jar
Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/fonts.yml
@@ -0,0 +1,47 @@
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Fonts

on:
push:
branches:
- '*'
tags:
- 'fonts/*-[0-9]*'
paths:
- 'flatlaf-fonts/**'
- '.github/workflows/fonts.yml'

jobs:
Release:
runs-on: ubuntu-latest
if: |
github.event_name == 'push' &&
github.repository == 'JFormDesigner/FlatLaf'
strategy:
matrix:
font:
- inter
- jetbrains-mono

steps:
- uses: actions/checkout@v3
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )

- name: Setup Java 11
uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt # pre-installed on ubuntu-latest
cache: gradle
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )

- name: Release a new stable version to Maven Central
run: ./gradlew :flatlaf-fonts-${{ matrix.font }}:build :flatlaf-fonts-${{ matrix.font }}:publish -Drelease=true
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
if: startsWith( github.ref, format( 'refs/tags/fonts/{0}-', matrix.font ) )
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -83,6 +83,8 @@ Addons
- [SwingX](flatlaf-swingx) - support for SwingX components
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
components
- [Fonts](flatlaf-fonts) - some font families bundled in easy-to-use and
redistributable JARs


Getting started
Expand Down
124 changes: 122 additions & 2 deletions flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
Expand Up @@ -114,6 +114,11 @@ public abstract class FlatLaf
private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters;

private static String preferredFontFamily;
private static String preferredLightFontFamily;
private static String preferredSemiboldFontFamily;
private static String preferredMonospacedFontFamily;

/**
* Sets the application look and feel to the given LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
Expand Down Expand Up @@ -631,6 +636,13 @@ private void initDefaultFont( UIDefaults defaults ) {
if( uiFont == null )
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );

// use preferred font family (if specified)
if( preferredFontFamily != null ) {
FontUIResource preferredFont = createCompositeFont( preferredFontFamily, uiFont.getStyle(), uiFont.getSize() );
if( !ActiveFont.isFallbackFont( preferredFont ) || ActiveFont.isDialogFamily( preferredFontFamily ) )
uiFont = preferredFont;
}

// get/remove "defaultFont" from defaults if set in properties files
// (use remove() to avoid that ActiveFont.createValue() gets invoked)
Object defaultFont = defaults.remove( "defaultFont" );
Expand Down Expand Up @@ -1323,6 +1335,90 @@ private static StyleableUI getStyleableUI( JComponent c ) {
private static boolean getUIMethodInitialized;
private static MethodHandle getUIMethod;

/**
* Returns the preferred font family to be used for (nearly) all fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredFontFamily() {
return preferredFontFamily;
}

/**
* Sets the preferred font family to be used for (nearly) all fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredFontFamily( String preferredFontFamily ) {
FlatLaf.preferredFontFamily = preferredFontFamily;
}

/**
* Returns the preferred font family to be used for "light" fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredLightFontFamily() {
return preferredLightFontFamily;
}

/**
* Sets the preferred font family to be used for "light" fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredLightFontFamily( String preferredLightFontFamily ) {
FlatLaf.preferredLightFontFamily = preferredLightFontFamily;
}

/**
* Returns the preferred font family to be used for "semibold" fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredSemiboldFontFamily() {
return preferredSemiboldFontFamily;
}

/**
* Sets the preferred font family to be used for "semibold" fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredSemiboldFontFamily( String preferredSemiboldFontFamily ) {
FlatLaf.preferredSemiboldFontFamily = preferredSemiboldFontFamily;
}

/**
* Returns the preferred font family to be used for monospaced fonts; or {@code null}.
*
* @since 3
*/
public static String getPreferredMonospacedFontFamily() {
return preferredMonospacedFontFamily;
}

/**
* Sets the preferred font family to be used for monospaced fonts.
* <p>
* <strong>Note</strong>: This must be invoked <strong>before</strong> setting
* the application look and feel.
*
* @since 3
*/
public static void setPreferredMonospacedFontFamily( String preferredMonospacedFontFamily ) {
FlatLaf.preferredMonospacedFontFamily = preferredMonospacedFontFamily;
}

//---- class FlatUIDefaults -----------------------------------------------

private class FlatUIDefaults
Expand Down Expand Up @@ -1457,9 +1553,16 @@ FontUIResource derive( Font baseFont, IntUnaryOperator scale ) {

// create font for family
if( families != null && !families.isEmpty() ) {
String preferredFamily = preferredFamily( families );
if( preferredFamily != null ) {
Font font = createCompositeFont( preferredFamily, newStyle, newSize );
if( !isFallbackFont( font ) || isDialogFamily( preferredFamily ) )
return toUIResource( font );
}

for( String family : families ) {
Font font = createCompositeFont( family, newStyle, newSize );
if( !isFallbackFont( font ) || family.equalsIgnoreCase( Font.DIALOG ) )
if( !isFallbackFont( font ) || isDialogFamily( family ) )
return toUIResource( font );
}
}
Expand Down Expand Up @@ -1488,9 +1591,26 @@ private FontUIResource toUIResource( Font font ) {
: new FontUIResource( font );
}

private boolean isFallbackFont( Font font ) {
private static boolean isFallbackFont( Font font ) {
return Font.DIALOG.equalsIgnoreCase( font.getFamily() );
}

private static boolean isDialogFamily( String family ) {
return family.equalsIgnoreCase( Font.DIALOG );
}

private static String preferredFamily( List<String> families ) {
for( String family : families ) {
family = family.toLowerCase( Locale.ENGLISH );
if( family.endsWith( " light" ) || family.endsWith( "-thin" ) )
return preferredLightFontFamily;
if( family.endsWith( " semibold" ) || family.endsWith( "-medium" ) )
return preferredSemiboldFontFamily;
if( family.equals( "monospaced" ) )
return preferredMonospacedFontFamily;
}
return null;
}
}

//---- class ImageIconUIResource ------------------------------------------
Expand Down
123 changes: 94 additions & 29 deletions flatlaf-core/src/main/java/com/formdev/flatlaf/util/HiDPIUtils.java
Expand Up @@ -16,6 +16,7 @@

package com.formdev.flatlaf.util;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.GlyphVector;
Expand Down Expand Up @@ -141,37 +142,101 @@ public static float computeTextYCorrection( Graphics2D g ) {
if( !useTextYCorrection() || !SystemInfo.isWindows )
return 0;

if( !SystemInfo.isJava_9_orLater )
return UIScale.getUserScaleFactor() > 1 ? -UIScale.scale( 0.625f ) : 0;
if( !SystemInfo.isJava_9_orLater ) {
// Java 8
float scaleFactor = getUserScaleFactor();
if( scaleFactor > 1 ) {
switch( g.getFont().getFamily() ) {
case "Segoe UI":
case "Segoe UI Light":
case "Segoe UI Semibold":
return -((scaleFactor == 2.25f || scaleFactor == 4f ? 0.875f : 0.625f) * scaleFactor);

case "Noto Sans":
case "Open Sans":
return -(0.3f * scaleFactor);

case "Verdana":
return -((scaleFactor < 2 ? 0.4f : 0.3f) * scaleFactor);
}
}
} else {
// Java 9 and later

// Text is painted at slightly different Y positions depending on scale factor
// and Y position of component.
// The exact reason is not yet known (to me), but there are several factors:
// - fractional scale factors result in fractional component Y device coordinates
// - fractional text Y device coordinates are rounded for horizontal lines of characters
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
// - Java adds 0.5 to X/Y positions before drawing string in BufferedTextPipe.enqueueGlyphList()

// this is not the optimal solution, but works very good in most cases
// (tested with class FlatPaintingStringTest on Windows 11)

switch( g.getFont().getFamily() ) {
case "Segoe UI":
case "Segoe UI Light":
case "Segoe UI Semibold":
case "Verdana":
case Font.DIALOG:
case Font.SANS_SERIF:
return correctionForScaleY( g, CORRECTION_SEGOE_UI );

case "Tahoma":
return correctionForScaleY( g, CORRECTION_TAHOMA );

case "Inter":
case "Inter Light":
case "Inter Semi Bold":
case "Roboto":
return correctionForScaleY( g, CORRECTION_INTER );

case "Noto Sans":
case "Open Sans":
return correctionForScaleY( g, CORRECTION_OPEN_SANS );
}
}

AffineTransform t = g.getTransform();
double scaleY = t.getScaleY();
if( scaleY < 1.25 )
return 0;
return 0;
}

private static final float[]
SCALE_FACTORS = { 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 3f, 3.5f, 4f },

CORRECTION_SEGOE_UI = { -0.5f, -0.5f, -0.625f, -0.75f, -0.75f, -0.75f, -0.75f, -0.75f, -0.875f },
CORRECTION_TAHOMA = { -0.25f, -0.25f, -0.25f, -0f, -0.125f, -0.125f, -0.125f, -0.125f, -0f },
CORRECTION_INTER = { -0.25f, -0.25f, -0.25f, -0f, -0.125f, -0.125f, -0f, -0.25f, -0f },
CORRECTION_OPEN_SANS = { -0.5f, -0.25f, -0.25f, -0f, -0.25f, -0.25f, -0f, -0.25f, -0.25f };

private static float correctionForScaleY( Graphics2D g, float[] correction ) {
if( correction.length != 9 )
throw new IllegalArgumentException();

double scaleY = g.getTransform().getScaleY();
return (scaleY < 1.25) ? 0 : correction[scaleFactor2index( (float) scaleY )];
}

private static int scaleFactor2index( float scaleFactor ) {
for( int i = 0; i < SCALE_FACTORS.length; i++ ) {
if( scaleFactor <= SCALE_FACTORS[i] )
return i;
}
return SCALE_FACTORS.length - 1;
}

private static Boolean useDebugScaleFactor;

private static boolean useDebugScaleFactor() {
if( useDebugScaleFactor == null )
useDebugScaleFactor = FlatSystemProperties.getBoolean( "FlatLaf.debug.HiDPIUtils.useDebugScaleFactor", false );
return useDebugScaleFactor;
}

// Text is painted at slightly different Y positions depending on scale factor
// and Y position of component.
// The exact reason is not yet known (to me), but there are several factors:
// - fractional scale factors result in fractional component Y device coordinates
// - fractional text Y device coordinates are rounded for horizontal lines of characters
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
// - Java adds 0.5 to X/Y positions before drawing string in BufferedTextPipe.enqueueGlyphList()

// this is not the optimal solution, but works very good in most cases
// (tested with class FlatPaintingStringTest on Windows 10 with font "Segoe UI")
if( scaleY <= 1.25 )
return -0.875f;
if( scaleY <= 1.5 )
return -0.625f;
if( scaleY <= 1.75 )
return -0.875f;
if( scaleY <= 2.0 )
return -0.75f;
if( scaleY <= 2.25 )
return -0.875f;
if( scaleY <= 3.5 )
return -0.75f;
return -0.875f;
private static float getUserScaleFactor() {
return !useDebugScaleFactor()
? UIScale.getUserScaleFactor()
: Float.parseFloat( System.getProperty( "FlatLaf.debug.HiDPIUtils.debugScaleFactor", "1" ) );
}

/**
Expand Down
2 changes: 2 additions & 0 deletions flatlaf-demo/build.gradle.kts
Expand Up @@ -22,6 +22,7 @@ plugins {
dependencies {
implementation( project( ":flatlaf-core" ) )
implementation( project( ":flatlaf-extras" ) )
implementation( project( ":flatlaf-fonts-inter" ) )
implementation( project( ":flatlaf-intellij-themes" ) )
implementation( "com.miglayout:miglayout-swing:5.3" )
implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
Expand All @@ -32,6 +33,7 @@ tasks {
jar {
dependsOn( ":flatlaf-core:jar" )
dependsOn( ":flatlaf-extras:jar" )
dependsOn( ":flatlaf-fonts-inter:jar" )
dependsOn( ":flatlaf-intellij-themes:jar" )
// dependsOn( ":flatlaf-natives-jna:jar" )

Expand Down

0 comments on commit 24bc7fb

Please sign in to comment.