[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-openjfx-dev
Subject:    Re: Support for Ligatures
From:       Scott Palmer <swpalmer () gmail ! com>
Date:       2022-10-25 2:25:18
Message-ID: 745B02B6-B3F5-496E-960D-A24AE3C8BFE9 () gmail ! com
[Download RAW message or body]

I guess everything you've written below about querying and requesting features still \
falls into the hole of "stuff we could do with Swing, but can't do with JavaFX".  I \
don't use Swing anymore, but every once in a while I run into one of these issues. \
There are workarounds for some, like NSMenuFX to get proper menu support on macOS, or \
using AWT Desktop support in combination with JavaFX to get the missing support for \
the system tray, dock, opening documents with the OS-defined default handler, etc... \
but it's less than ideal.   However, this issue doesn't appear to have any \
workaround.

I did a quick search in the JavaFX code for ligature support and it seems there is \
quite a bit of incomplete support in many parts of the font processing.  E.g. \
com.sun.javafx.scene.control.skin.Utils contains the commented out block that appears \
to be from older AWT code:

    private static boolean requiresComplexLayout(Font font, String string) {
        /*        Map attrs = font.getAttributes();
           if (contains(attrs, KERNING, KERNING_ON) ||
           contains(attrs, LIGATURES, LIGATURES_ON) ||
           (attrs.containsKey(TRACKING) && attrs.get(TRACKING) != null)) {
           return true;
           }
           return isComplexLayout(string.toCharArray(), 0, string.length());
         */
        return false;
    }

So complexLayout is always ‘false', which is good because where it is used the path \
for 'true' looks like:  if (complexLayout) {
            // TODO needs implementation
            return 0;
        } else {


com.sun.javafx.font.FontResources defines a bunch of constants related to ligatures, \
but they don't appear to be used anywhere.  Looks like they are intended for the \
value returned by getFeatures() in FontResource and PGFont.

com.sun.javafx.font.PrismFont and the interface it implements PGFont (what does PG \
stand for?) defines a getFeatures method:  /*
     * Returns the features the user has requested.
     * (kerning, ligatures, etc)
     */
    @Override public int getFeatures() {
        return features;
    }

but features is always 0, with no means to set it.

com.sun.javafx.text.GlyphLayout where ‘features' is used in two places compares the \
features of Font to FontResource. PrismFont defaults to 0, and the PrismFontFile \
implementation of FontResource returns -1, so for GlyphLayout  the supported features \
are always "everything" and the requested features are always "nothing", so boolean \
feature = false, always. This is used to compute ‘complex' (initially false)  if \
                (!complex) {
                        complex = feature || \
ScriptMapper.isComplexCharCode(codePoint);  }
So ScriptMapper is the only thing really deciding what's ‘complex'… which seems \
to bring me back to what you've stated, that required ligatures like those needed for \
Arabic are supported.  Now I wonder if ‘feature' was true would my Fira Code \
experiment render correctly or is there a lot more to it than that?

It seems there is some otherwise ‘dead' code already in place to support requesting \
these openType features. Is exposing an API to initialize the features of \
FontResource enough to get some meaningful results?

I was going to try some experiments, but I'm unable to build OpenJFX on my Mac for \
some reason:

> > Task :graphics:compileJava FAILED
> You specified both --module-source-path and a sourcepath. These options are \
>                 mutually exclusive. Ignoring sourcepath.
> error: option --upgrade-module-path cannot be used together with --release
> Usage: javac <options> <source files>
> use --help for a list of possible options

 (using JDK 17 running a simple ./gradlew)
I didn't have trouble when I last built it a couple years ago, so I'm not sure what's \
changed.

Cheers,

Scott

> On Oct 24, 2022, at 3:43 PM, Philip Race <philip.race@oracle.com> wrote:
> 
> FX does (of course) support required ligatures, meaning those without which some \
> script (eg Arabic) can't even be rendered.
> 
> But that is implementation, no API.
> 
> So this is about adding an API to request optional ligatures - and other OpenType \
> features. For example I think we'd want to support things like small caps etc.
> 
> Of course we'd need to make sure all the measuring code is up to that .. and BTW
> the APIs to do measurement probably should be in the queue ahead of this ..
> 
> And I am not sure about just an API to request ligatures without an API to query
> if ligatures are available for a font. However that may turn out to be tricky for a
> few reasons, but we should at least study it.
> 
> And to try to answer the "when" question .. it is on a "desired" list in my head \
> and maybe even on a wiki somewhere .. but no concrete timetable exists.
> 
> But it is good to get feedback like this so we know it is interesting to \
> developers. 
> -phil.
> 
> On 10/24/22 12:07 PM, Scott Palmer wrote:
> > Something I noticed while experimenting with RichTextFX, when I set it to use \
> > Fira Code for the font, like I do in NetBeans, I see that JavaFX doesn't support \
> > ligatures.  I found this issue that's been around for quite some time: \
> > https://bugs.openjdk.org/browse/JDK-8091616 
> > Is there any drive to get this implemented within the next few releases?  I would \
> > help, but unfortunately I suspect it will take more time than I can commit to it. \
> > I'm hoping that eliminating some of the remaining gaps between what JavaFX \
> > supports and Swing supports would be a priority, as it removes some barriers to \
> > JavaFX adoption... but maybe not? 
> > Regards,
> > 
> > Scott
> 


[Attachment #3 (unknown)]

<html><head><meta http-equiv="content-type" content="text/html; \
charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: \
space; line-break: after-white-space;"><div dir="auto" style="overflow-wrap: \
break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div dir="auto" \
style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: \
after-white-space;"><div dir="auto" style="overflow-wrap: break-word; \
-webkit-nbsp-mode: space; line-break: after-white-space;">I guess everything you've \
written below about querying and requesting features still falls into the hole of \
"stuff we could do with Swing, but can't do with JavaFX". &nbsp;I don't use Swing \
anymore, but every once in a while I run into one of these issues. There are \
workarounds for some, like NSMenuFX to get proper menu support on macOS, or using AWT \
Desktop support in combination with JavaFX to get the missing support for the system \
tray, dock, opening documents with the OS-defined default handler, etc... but it's \
less than ideal. &nbsp; However, this issue doesn't appear to have any \
workaround.</div><div dir="auto" style="overflow-wrap: break-word; -webkit-nbsp-mode: \
space; line-break: after-white-space;"><div><br></div><div>I did a quick search in \
the JavaFX code for ligature support and it seems there is quite a bit of incomplete \
support in many parts of the font processing. &nbsp;E.g. \
com.sun.javafx.scene.control.skin.Utils contains the commented out block that appears \
to be from older AWT code:</div><div><br></div><div><div><font face="Courier \
New">&nbsp; &nbsp; private static boolean requiresComplexLayout(Font font, String \
string) {</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; /* \
&nbsp; &nbsp; &nbsp; &nbsp;Map attrs = font.getAttributes();</font></div><div><font \
face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (contains(attrs, \
KERNING, KERNING_ON) ||</font></div><div><font face="Courier New">&nbsp; &nbsp; \
&nbsp; &nbsp; &nbsp; &nbsp;contains(attrs, LIGATURES, LIGATURES_ON) \
||</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
&nbsp;(attrs.containsKey(TRACKING) &amp;&amp; attrs.get(TRACKING) != null)) \
{</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
&nbsp;return true;</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; \
&nbsp; &nbsp; &nbsp;}</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; \
&nbsp; &nbsp; &nbsp;return isComplexLayout(string.toCharArray(), 0, \
string.length());</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; \
&nbsp; &nbsp;*/</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; \
return false;</font></div><div><font face="Courier New">&nbsp; &nbsp; \
}</font></div><div><br></div><div>So complexLayout is always ‘false', which is good \
because where it is used the path for 'true' looks like:</div><div><div><font \
face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; if (complexLayout) \
{</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
// TODO needs implementation</font></div><div><font face="Courier New">&nbsp; &nbsp; \
&nbsp; &nbsp; &nbsp; &nbsp; return 0;</font></div><div><font face="Courier \
New">&nbsp; &nbsp; &nbsp; &nbsp; } else \
{</font></div></div><div><br></div><div><br></div><div>com.sun.javafx.font.FontResources \
defines a bunch of constants related to ligatures, but they don't appear to be used \
anywhere. &nbsp;Looks like they are intended for the value returned by getFeatures() \
in FontResource and PGFont.</div><div><br></div><div>com.sun.javafx.font.PrismFont \
and the interface it implements PGFont (what does PG stand for?) defines a \
getFeatures method:</div><div><div><font face="Courier New">&nbsp; &nbsp; \
/*</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp;* Returns the \
features the user has requested.</font></div><div><font face="Courier New">&nbsp; \
&nbsp; &nbsp;* (kerning, ligatures, etc)</font></div><div><font face="Courier \
New">&nbsp; &nbsp; &nbsp;*/</font></div><div><font face="Courier New">&nbsp; &nbsp; \
@Override public int getFeatures() {</font></div><div><font face="Courier New">&nbsp; \
&nbsp; &nbsp; &nbsp; return features;</font></div><div><font face="Courier \
New">&nbsp; &nbsp; }</font></div><div><br></div><div>but features is always 0, with \
no means to set it.</div><div><br></div><div>com.sun.javafx.text.GlyphLayout where \
‘features' is used in two places compares the features of Font to FontResource. \
PrismFont defaults to 0, and the PrismFontFile implementation of FontResource returns \
-1, so for GlyphLayout &nbsp;the supported features are always "everything" and the \
requested features are always "nothing", so boolean feature = false, always. This is \
used to compute ‘complex' (initially false)</div><div><div><font face="Courier \
New">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if \
(!complex) {</font></div><div><font face="Courier New">&nbsp; &nbsp; &nbsp; &nbsp; \
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; complex = feature || \
ScriptMapper.isComplexCharCode(codePoint);</font></div><div><font face="Courier \
New">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
}</font></div><div>So ScriptMapper is the only thing really deciding what's \
‘complex'… which seems to bring me back to what you've stated, that required \
ligatures like those needed for Arabic are supported. &nbsp;Now I wonder if \
‘feature' was true would my Fira Code experiment render correctly or is there a lot \
more to it than that?</div><div><br></div><div>It seems there is some otherwise \
‘dead' code already in place to support requesting these openType \
features.</div><div>Is exposing an API to initialize the features of FontResource \
enough to get some meaningful results?</div><div><br></div><div>I was going to try \
some experiments, but I'm unable to build OpenJFX on my Mac for some \
reason:</div><div><br></div><div><blockquote type="cite"><p style="margin: 0px; \
font-stretch: normal; line-height: normal; font-family: Hack; color: rgb(255, 99, \
85); background-color: rgba(255, 255, 255, 0.9);"><span \
style="font-variant-ligatures: no-common-ligatures"><b>&gt; Task \
:graphics:compileJava</b> FAILED</span></p> <p style="margin: 0px; font-stretch: \
normal; line-height: normal; font-family: Hack; color: rgb(0, 255, 0); \
background-color: rgba(255, 255, 255, 0.9);"><span style="font-variant-ligatures: \
no-common-ligatures">You specified both --module-source-path and a sourcepath. These \
options are mutually exclusive. Ignoring sourcepath.</span></p> <p style="margin: \
0px; font-stretch: normal; line-height: normal; font-family: Hack; color: rgb(0, 255, \
0); background-color: rgba(255, 255, 255, 0.9);"><span style="font-variant-ligatures: \
no-common-ligatures">error: option --upgrade-module-path cannot be used together with \
--release</span></p> <p style="margin: 0px; font-stretch: normal; line-height: \
normal; font-family: Hack; color: rgb(0, 255, 0); background-color: rgba(255, 255, \
255, 0.9);"><span style="font-variant-ligatures: no-common-ligatures">Usage: javac \
&lt;options&gt; &lt;source files&gt;</span></p> <p style="margin: 0px; font-stretch: \
normal; line-height: normal; font-family: Hack; color: rgb(0, 255, 0); \
background-color: rgba(255, 255, 255, 0.9);"><span style="font-variant-ligatures: \
no-common-ligatures">use --help for a list of possible \
options</span></p></blockquote><div><p style="margin: 0px; font-stretch: normal; \
line-height: normal; font-family: Hack; color: rgb(0, 255, 0); background-color: \
rgba(255, 255, 255, 0.9);"><span style="font-variant-ligatures: \
no-common-ligatures"><br></span></p></div></div></div><div><span style="caret-color: \
rgb(0, 0, 0); color: rgb(0, 0, 0);">&nbsp;(using JDK 17 running a simple \
./gradlew)</span></div><div><font color="#000000">I didn't have trouble when I last \
built it a couple years ago, so I'm not sure what's \
changed.</font></div><div><br></div></div><div>Cheers,</div><div><br></div><div>Scott</div><div><br><blockquote \
type="cite"><div>On Oct 24, 2022, at 3:43 PM, Philip Race \
&lt;philip.race@oracle.com&gt; wrote:</div><br \
class="Apple-interchange-newline"><div> <meta http-equiv="Content-Type" \
content="text/html; charset=utf-8">  
  <div>
    FX does (of course) support required ligatures, meaning those
    without which some script (eg Arabic)<br>
    can't even be rendered.<br>
    <br>
    But that is implementation, no API.<br>
    <br>
    So this is about adding an API to request optional ligatures - and
    other OpenType features.<br>
    For example I think we'd want to support things like small caps etc.<br>
    <br>
    Of course we'd need to make sure all the measuring code is up to
    that .. and BTW<br>
    the APIs to do measurement probably should be in the queue ahead of
    this ..<br>
    <br>
    And I am not sure about just an API to request ligatures without an
    API to query<br>
    if ligatures are available for a font. However that may turn out to
    be tricky for a<br>
    few reasons, but we should at least study it.<br>
    <br>
    And to try to answer the "when" question .. it is on a "desired"
    list in my head and maybe<br>
    even on a wiki somewhere .. but no concrete timetable exists.<br>
    <br>
    But it is good to get feedback like this so we know it is
    interesting to developers.<br>
    <br>
    -phil.<br>
    <br>
    <div class="moz-cite-prefix">On 10/24/22 12:07 PM, Scott Palmer
      wrote:<br>
    </div>
    <blockquote type="cite" \
cite="mid:D2536978-0591-4BA9-AD3D-879057A10877@gmail.com">  
      <div style="display: block;">Something I noticed while
        experimenting with RichTextFX, when I set it to use Fira Code
        for the font, like I do in NetBeans, I see that JavaFX doesn't
        support ligatures. &nbsp;I found this issue that's been around for
        quite some time:</div>
      <div style="display: block;">
        <div style="-webkit-user-select: all; -webkit-user-drag:
          element; display: inline-block;" class="apple-rich-link" draggable="true" \
role="link" data-url="https://bugs.openjdk.org/browse/JDK-8091616"><a \
style="border-radius:10px;font-family:-apple-system,  Helvetica, Arial,
sans-serif;display:block;-webkit-user-select:none;width:300px;user-select:none;-webkit \
-user-modify:read-only;user-modify:read-only;overflow:hidden;text-decoration:none;" \
class="lp-rich-link" rel="nofollow" \
href="https://bugs.openjdk.org/browse/JDK-8091616" dir="ltr" role="button" \
                draggable="false" width="300" moz-do-not-send="true">
            <table style="table-layout:fixed;border-collapse:collapse;width:300px;background-color:#E5E6E9;font-family:-apple-system,
                
              Helvetica, Arial, sans-serif;" class="lp-rich-link-emailBaseTable" \
width="300" cellspacing="0" cellpadding="0" border="0">  <tbody>
                <tr>
                  <td vertical-align="center">
                    <table style="font-family:-apple-system, Helvetica,
                      Arial,
                      sans-serif;table-layout:fixed;background-color:rgba(229,
                      230, 233, 1);" class="lp-rich-link-captionBar" width="300" \
cellspacing="0" cellpadding="0" bgcolor="#E5E6E9">  <tbody>
                        <tr>
                          <td style="padding:8px 0px 8px 0px;" \
class="lp-rich-link-captionBar-textStackItem">  <div style="max-width:100%;margin:0px \
                16px
                              0px 16px;overflow:hidden;" \
class="lp-rich-link-captionBar-textStack">  <div \
style="word-wrap:break-word;font-weight:500;font-size:12px;overflow:hidden;text-overflow:ellipsis;text-align:left;" \
class="lp-rich-link-captionBar-textStack-topCaption-leading"><a rel="nofollow" \
href="https://bugs.openjdk.org/browse/JDK-8091616" style="text-decoration: none" \
draggable="false" moz-do-not-send="true"><font style="" color="#272727">[JDK-8091616] \
                Prism: font: ligature and kerning
                                    support - Java Bug System</font></a></div>
                              <div \
style="word-wrap:break-word;font-weight:400;font-size:11px;overflow:hidden;text-overflow:ellipsis;text-align:left;" \
class="lp-rich-link-captionBar-textStack-bottomCaption-leading"><a rel="nofollow" \
href="https://bugs.openjdk.org/browse/JDK-8091616" style="text-decoration: none" \
draggable="false" moz-do-not-send="true"><font style="" \
color="#808080">bugs.openjdk.org</font></a></div>  </div>
                          </td>
                          <td style="padding:6px 12px 6px 0px;" \
class="lp-rich-link-captionBar-rightIconItem" width="36"><a rel="nofollow" \
href="https://bugs.openjdk.org/browse/JDK-8091616" draggable="false" \
moz-do-not-send="true"><span \
id="cid:part1.pgghvLBj.kKB35Rev@oracle.com">&lt;jira-favicon-hires.png&gt;</span></a></td>
  </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
          </a></div>
      </div>
      <div><br>
      </div>
      <div>Is there any drive to get this implemented within the next
        few releases? &nbsp;I would help, but unfortunately I suspect it will
        take more time than I can commit to it.</div>
      <div>I'm hoping that eliminating some of the remaining gaps
        between what JavaFX supports and Swing supports would be a
        priority, as it removes some barriers to JavaFX adoption... but
        maybe not?</div>
      <div><br>
      </div>
      <div>Regards,</div>
      <div><br>
      </div>
      <div>Scott</div>
    </blockquote>
    <br>
  </div>
</div></blockquote></div><br></div></div></div></div></body></html>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic