%D \module
%D   [      file=m-fonts-plugins,
%D        version=2016.10.10,
%D          title=\CONTEXT\ Fonts,
%D       subtitle=Font Engine Plugins,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D See source code for comments. I wrote this a follow up on a presentation by Kai
%D Eigner at an NTG meeting, then left it for a while, and sort of finalized it the
%D last quarter of 2016. As I don't use this module, apart from maybe testing
%D something, it is not guaranteed to work (but fixing should be a no real problem
%D as I expect apis to be stable). Plugins like this can interfere with other
%D functionality in \CONTEXT\ so don't expect too much support. The two modules
%D mentioned below should work in the generic loader too. It's anyhow an
%D illustration of how \type {ffi} be used in a practical application.
%D
%D I'm not sure if Idris will ever need this but the code has been used for some
%D articles so that's why it's eventually shipped.
%D
%D The library is supposed to be present in
%D
%D \starttyping
%D .../tex/texmf-win64/bin/lib/luatatex/harfbuzz/libharfbuzz-0.dll
%D .../tex/texmf-win64/bin/lib/luametatex/harfbuzz/libharfbuzz-0.dll
%D
%D .../tex/texmf-*/bin/lib/luatatex/harfbuzz/libharfbuzz.so
%D .../tex/texmf-*/bin/lib/luametatex/harfbuzz/libharfbuzz.so
%D \stoptyping
%D
%D It might be found on the system if paths are set but with libraries that render
%D (font) stuff it's best to rely on what you explictly installed. When you install
%D files there make sure to run \type {mtxrun --generate}. Keep in mind that we don't
%D officially support such dependencies (bug-wise).
%D
%D In mkiv we support binary and library, and in lmtx binary and internal where we
%D default to library or internal as binary is not that fast (more meant as a
%D playground I guess). You can track loading with:
%D
%D \starttyping
%D \enabletrackers[resolvers.ffilib]
%D \stoptyping
%D
%D This file has always been in the distribution but per end april 2021 the font-txt,
%D font-phb and font-phb-imp-* files are in the distrinbution too. It's a side effect
%D of some cleanup of the (luametatex) source tree (where the optional module was not
%D yet in sync with the other optional ones). This module is mostly for myself and
%D Idris if only because it is not tested for interferences with all kind of other
%D font code (and it's unlikely to happen), so don't depend on this!

% \starttext
%
%     \definefontfeature [native] [default]
%       [mode=plug,
%        features=harfbuzz,
%        shaper=native]
%
%     \definefontfeature [uniscribe] [default]
%       [mode=plug,
%        features=harfbuzz,
%        shaper=uniscribe]
%
%     \definefontfeature [binary] [default]
%       [mode=plug,
%        method=binary,
%        features=harfbuzz,
%        shaper=uniscribe]
%
%     % \nohyphens
%     \definedfont[Serif*default]   fiets \par % \input tufte \par
%     \definedfont[Serif*native]    fiets \par % \input tufte \par
%     \definedfont[Serif*uniscribe] fiets \par % \input tufte \par
%     \definedfont[Serif*binary]    fiets \par % \input tufte \par
%
% \stoptext


\registerctxluafile{font-phb}{autosuffix}

\startluacode

    local function processlist(data)
        local list    = data.list
        local timings = data.results
        for i=1,#list do
            local name = list[i]
            local data = timings[name]
            local none = data["context none"] or 0
            local node = data["context node"] or 0
            if node > 0.1 then
                context.starttabulate { "|l|c|c|c|c|c|" }
                    context.NC() context.bold(name)
                    context.NC() context([[$t$]])
                    context.NC() context([[$t - t_{\hbox{\tx none}}$]])
                    context.NC() context([[$t - t_{\hbox{\tx node}}$]])
                    context.NC() context([[$t / t_{\hbox{\tx node}}$]])
                    context.NC() context([[$\frac{t - t_{\hbox{\txx none}}}{t_{\hbox{\txx node}} - t_{\hbox{\txx none}}}$]])
                    context.NC() context.NR()
                    context.TL()
                    for k, v in table.sortedhash(data) do
                        context.NC() context(k)
                        context.NC() context("%0.2f",v)
                        context.NC() context("%0.2f",v - none)
                        context.NC() context("%0.2f",v - node)
                        context.NC() context("%0.2f",v / node)
                        context.NC() if node ~= none then context("%0.2f",(v-none) / (node-none)) end
                        context.NC() context.NR()
                    end
                context.stoptabulate()
            end
        end
    end

    moduledata.plugins = {
        processlist = processlist,
    }

\stopluacode

\continueifinputfile{m-fonts-plugins.mkiv}

\usemodule[art-01]

\starttext

\edef\tufte{\cldloadfile{tufte.tex}}
\edef\khatt{\cldloadfile{khatt-ar.tex}}

\startbuffer[latin-definitions]
\definefont[TestA][Serif*test]
\definefont[TestB][SerifItalic*test]
\definefont[TestC][SerifBold*test]
\stopbuffer

\startbuffer[latin-text]
\TestA \tufte \par
\TestB \tufte \par
\TestC \tufte \par
\dorecurse {10} {%
    \TestA Fluffy Test Font A
    \TestB Fluffy Test Font B
    \TestC Fluffy Test Font C
}\par
\stopbuffer

\startbuffer[arabic-definitions]
\definedfont[Arabic*test at 14pt]
\setupinterlinespace[line=18pt]
\setupalign[r2l]
\stopbuffer

\startbuffer[arabic-text]
\dorecurse {10} {
    \khatt\space
    \khatt\space
    \khatt
    \blank
}
\stopbuffer

\startbuffer[mixed-definitions]
\definefont[TestL][Serif*test]
\definefont[TestA][Arabic*test at 14pt]
\setupinterlinespace[line=18pt]
\setupalign[r2l]
\stopbuffer

\startbuffer[mixed-text]
\dorecurse {2} {
    {\TestA\khatt\space\khatt\space\khatt}
    {\TestL\lefttoright\tufte}
    \blank
    \dorecurse{10}{%
        {\TestA وَ قَرْمِطْ بَيْنَ الْحُرُوفِ؛ فَإِنَّ}
        {\TestL\lefttoright A snippet text that makes no sense.}
    }
}
\stopbuffer

\definefontfeature
  [test-none]
  [mode=none]

\definefontfeature
  [test-base]
  [mode=base,
   liga=yes,
   kern=yes]

% no tlig and no analyze

\definefontfeature
  [test-node]
  [mode=node,
   script=auto,
   autoscript=position,
   autolanguage=position,
   ccmp=yes,
   liga=yes,
 % rlig=yes,
 % hlig=yes,
 % dlig=yes,
   clig=yes,
   kern=yes,
   mark=yes,
   mkmk=yes,
   curs=yes]

\definefontfeature
  [test-text]
  [mode=plug,
   features=text]

\definefontfeature
  [test-native]
  [mode=plug,
   features=harfbuzz,
  %liga=yes,
  %kern=yes,
   shaper=native]

\definefontfeature
  [test-uniscribe]
  [mode=plug,
   features=harfbuzz,
  %liga=yes,
  %kern=yes,
   shaper=uniscribe]

\definefontfeature
  [test-binary]
  [mode=plug,
   features=harfbuzz,
  %liga=yes,
  %kern=yes,
   shaper=uniscribe,
   method=binary]

\definefontfeature
  [arabic-node]
  [arabic]
  [salt=yes] % seems to be needed for husayni

\definefontfeature
  [arabic-native]
  [mode=plug,
   features=harfbuzz,
 % method=binary,
% method=internal,
   script=arab,language=dflt,
%    ccmp=yes,
%    init=yes,medi=yes,fina=yes,isol=yes,
%    liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes,
%    mark=yes,mkmk=yes,kern=yes,curs=yes,
   shaper=native]

\definefontfeature
  [arabic-uniscribe]
  [mode=plug,
   features=harfbuzz,
   script=arab,language=dflt,
%    ccmp=yes,
%    init=yes,medi=yes,fina=yes,isol=yes,
%    liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes,
%    mark=yes,mkmk=yes,kern=yes,curs=yes,
   shaper=uniscribe]

\starttexdefinition RunLatinTest #1#2#3#4#5
    \start
        \dontcomplain
        \definefontfeature[test][test-#4]
        \writestatus{warning}{#1 #3 #4 (1 initial run)}
        \page
        \startluacode
            collectgarbage("collect")
        \stopluacode
        \title{#1 #3 #4}
        \start
            \getbuffer[#5-definitions]
            \showfontkerns
            \showmakeup[discretionary]
          % \enabletrackers[fonts.plugins.hb.colors]%
            \testfeatureonce{1}{
                \getbuffer[#5-text]
            }
        \stop
        \page
        \startluacode
            collectgarbage("collect")
        \stopluacode
        \ifnum#2>1\relax
            \writestatus{warning}{#1 #3 #4 (#2 timing runs)}
            \start
                \getbuffer[#5-definitions]
                \testfeatureonce{#2}{
                    \setbox\scratchbox\hbox{\getbuffer[#5-text]}
                }
            \stop
            \writestatus{warning}{done}
        \fi
        \startluacode
            document.collected_timings.timings["#5"].results["#1"]["#3 #4"] = \elapsedtime\space
            collectgarbage("collect")
        \stopluacode
    \stop
\stoptexdefinition

\starttexdefinition RunArabicTest #1#2#3#4#5
    \start
        \dontcomplain
        \definefontsynonym[Arabic][#1]
        \definefontfeature[test][arabic-#4]
        \writestatus{warning}{#1 #3 #4 #5 (1 initial run)}
        \page
        \startluacode
            collectgarbage("collect")
        \stopluacode
        \title{#1 #3 #4}
        \start
            \getbuffer[#5-definitions]
          % \enabletrackers[fonts.plugins.hb.colors]%
            \testfeatureonce{1}{
                \setupalign[flushleft] % easier to compare
                \getbuffer[#5-text]
            }
            \par
        \stop
        \page
        \ifnum#2>1\relax
            \writestatus{warning}{#1 #3 #4 #5 (#2 timing runs)}
            \start
                \getbuffer[#5-definitions]
                \testfeatureonce{#2}{
                    \setbox\scratchbox\hbox{\getbuffer[#5-text]}
                }
            \stop
            \writestatus{warning}{done}
        \fi
        \startluacode
            document.collected_timings.timings["#5"].results["#1"]["#3 #4"] = \elapsedtime\space
            collectgarbage("collect")
        \stopluacode
    \stop
\stoptexdefinition

\startsubject[title=Remark]

These tests are no longer representative because in mode node we have a lot of
additional features (control options, tracing, dynamics, user features) kicking
in that impact runtime because they need to be checked. The same is true for
discretionaries. On the average the font processing time is not that much the
bottleneck anyway, also given that typesetting with \TEX\ has always been about
full control over matters. But we keep this module around. When run with \LMTX\
\LUATEX\ is actually \LUAMETATEX .

\stopsubject

\page

\startluacode

    local processlist = moduledata.plugins.processlist

    local data = {
        timings = { },
        engine  = jit and "luajittex" or "luatex",
    }

    document.collected_timings = data

    -- LATIN

    local list = {
       "modern",
       "pagella",
       "dejavu",
       "cambria",
       "ebgaramond",
       "lucidaot"
    }

    data.timings["latin"] = {
        list    = list,
        results = table.setmetatableindex("table"),
    }

    for i=1,#list do

        local name = list[i]

        context.setupbodyfont { name }
        context.RunLatinTest (name, 100, "context",  "none",      "latin")
        context.RunLatinTest (name, 100, "context",  "base",      "latin")
        context.RunLatinTest (name, 100, "context",  "node",      "latin")
        context.RunLatinTest (name, 100, "harfbuzz", "native",    "latin")
        context.RunLatinTest (name, 100, "harfbuzz", "uniscribe", "latin")
     -- context.RunLatinTest (name,   1, "context",  "text",      "latin")
     -- context.RunLatinTest (name,   1, "harfbuzz", "binary",    "latin")

    end

    context(function()
        context.page()
        context.title((jit and "luajittex" or "luatex") .. " latin")
        processlist(data.timings["latin"])
        context.page()
    end)

    -- ARABIC

    local list = {
        "arabtype",
        "husayni",
    }

    data.timings["arabic"] = {
        list    = list,
        results = table.setmetatableindex("table")
    }

    for i=1,#list do

        local name = list[i]

        context.setupbodyfont { name }
        context.RunArabicTest (name, 100, "context",  "none",      "arabic")
        context.RunArabicTest (name, 100, "context",  "base",      "arabic")
        context.RunArabicTest (name, 100, "context",  "node",      "arabic")
        context.RunArabicTest (name, 100, "harfbuzz", "native",    "arabic")
        context.RunArabicTest (name, 100, "harfbuzz", "uniscribe", "arabic")
     -- context.RunArabicTest (name,   1, "context",  "text",      "arabic")
     -- context.RunArabicTest (name,   1, "harfbuzz", "binary",    "arabic")

    end

    context(function()
        context.page()
        context.title((jit and "luajittex" or "luatex") .. " arabic")
        processlist(data.timings["arabic"])
        context.page()
    end)

    -- MIXED

    local list = {
        "arabtype",
        "husayni"
    }

    data.timings["mixed"] = {
        list    = list,
        results = table.setmetatableindex("table")
    }

    for i=1,#list do

        local name = list[i]

        context.setupbodyfont { name }
        context.RunArabicTest (name, 100, "context",  "none",      "mixed")
        context.RunArabicTest (name, 100, "context",  "base",      "mixed")
        context.RunArabicTest (name, 100, "context",  "node",      "mixed")
        context.RunArabicTest (name, 100, "harfbuzz", "native",    "mixed")
        context.RunArabicTest (name, 100, "harfbuzz", "uniscribe", "mixed")
     -- context.RunArabicTest (name,   1, "context",  "text",      "mixed")
     -- context.RunArabicTest (name,   1, "harfbuzz", "binary",    "mixed")

    end

    context(function()
        context.page()
        context.title((jit and "luajittex" or "luatex") .. " mixed")
        processlist(data.timings["mixed"])
        context.page()
    end)

    context(function()
        table.save("m-fonts-plugins-timings-" .. (jit and "luajittex" or "luatex") .. ".lua",data)
    end)

\stopluacode

\stoptext
