ntg-context - mailing list for ConTeXt users
 help / color / mirror / Atom feed
From: Hans Hagen via ntg-context <ntg-context@ntg.nl>
To: mailing list for ConTeXt users <ntg-context@ntg.nl>,
	"amano.kenji" <amano.kenji@proton.me>
Cc: Hans Hagen <j.hagen@freedom.nl>
Subject: Re: Is rendering furigana over horizontal or vertical japanese text doable in ConTeXt?
Date: Sun, 21 Aug 2022 12:00:59 +0200	[thread overview]
Message-ID: <2b32e839-91a6-1b08-6c59-501ca2b5dd70@freedom.nl> (raw)
In-Reply-To: <CAHN0TNiaPxCA53_c7Hee-kB=f0kfKvJ0B-+CXgGMyo=JoetB+A@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1220 bytes --]

On 8/21/2022 10:24 AM, 黄复雄 via ntg-context wrote:
> Currently, the ruby module does not seem to support cjk fonts? I have
> a preliminary implementation of furigana(pinyin in Chinese) as:
Actually a few years ago I added some basic new features for doing 
vertical scripts effciently but (as often with these things) there was 
not that much follow up because no one seems to need / use it (or be 
triggered by the fact that it can be used).

The attached files show two methods ... manual work as well as semi 
automatic (one needs to patch one font file for some recent optimizations).

As you can see, rubies work ok. Now, before trying to improve this, it 
makes more sense to think about what kind of vertical support is 
actually needed becaus in order for that to work ok it really has to 
work with other mechanism as well and there is only so much that tex can 
do.

Hans

-----------------------------------------------------------------
                                           Hans Hagen | PRAGMA ADE
               Ridderstraat 27 | 8061 GH Hasselt | The Netherlands
        tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl
-----------------------------------------------------------------

[-- Attachment #2: test-directions-005.pdf --]
[-- Type: application/pdf, Size: 21019 bytes --]

[-- Attachment #3: test-directions-005.tex --]
[-- Type: text/plain, Size: 6922 bytes --]

\noheaderandfooterlines

% in font-imp-scripts, line 145, comment a few lines
%
%                 orientate = function(character)
%                     local width  = character.width or 0
%                     local height = character.height or 0
%                     local depth  = character.depth or 0
% --                     character.width       = height + depth + rightshift + rightshift
%                     character.height      = width - downshift
%                     character.depth       = shift
% --                     character.xoffset     = height + rightshift
% --                     character.yoffset     = - downshift
% --                     character.orientation = orientation
%                 end

\dontcomplain

\setuplayout[middle]

\starttext

\startluacode
    local nuts          = nodes.nuts

    local nextglyph     = nuts.traversers.glyph
    local nextnode      = nuts.traversers.node

    local newhlist      = nuts.pool.hlist
    local newglue       = nuts.pool.glue
    local newpenalty    = nuts.pool.penalty

    local getprev       = nuts.getprev
    local setnext       = nuts.setnext
    local getnext       = nuts.getnext
    local setprev       = nuts.setprev
    local getboth       = nuts.getboth
    local setboth       = nuts.setboth
    local setlink       = nuts.setlink
    local getlist       = nuts.getlist
    local setlist       = nuts.setlist
    local setwhd        = nuts.setwhd
    local getwhd        = nuts.getwhd
    local getid         = nuts.getid
    local getchar       = nuts.getchar

    local getbox        = nuts.getbox

    local getdimensions = nuts.dimensions

    local setorientation  = nuts.setorientation
    local getorientation  = nuts.getorientation

    local glyph_code    = nodes.nodecodes.glyph
    local kern_code     = nodes.nodecodes.kern

    function document.manipulate_one(boxnumber)

        local box  = getbox(1000)
        local list = getlist(b)
        local all  = { }

        for n, c, f in nextglyph, list do
            if c > 200 then
                all[n] = true
            end
        end

        local o = 4 * 65536

        for n, how in next, all do
            local prev, next = getboth(n)
            setboth(n)
            local l = newhlist(n)
            local w, h, d = getwhd(n)
            setlink(prev,l,next)
            if how then
                setwhd(l,h+d+o,w,0)
                setorientation(l,0x003,0,0,h,d-o)
            end
            if n == list then
                setlist(box,l)
            end
        end

    end

    local function flushrange(head,current,first,last)
        local prev = getprev(first)
        local next = getnext(last)
        local list = newhlist(first)
        setprev(first)
        setnext(last)
        local w, h, d = getdimensions(first)
        setwhd(list,h+d,w,0)
        setlink(prev,list,next)
        setorientation(list,0x001,0,0,h,d)
        if first == head then
            return list, list
        else
            return head, list
        end
    end

    local function flushchar(head,current)
        local next = getnext(current)
        local glue = newglue(n,655360)
        setlink(current,glue,next)
        return head, glue
    end

    function document.manipulate_two(boxnumber)

        local box     = getbox(1000)
        local head    = getlist(box)
        local first   = false
        local last    = false
        local current = head
        while current do
            local id = getid(current)
            if id == glyph_code then
                if getchar(current) < 200 then
                    if first then
                        last = current
                    else
                        first = current
                        last  = current
                    end
                else
                    if first then
                        head, current = flushrange(head,current,first,last)
                        first = false
                    end
                    head, current = flushchar(head,current)
                end
            elseif id == kern_code then
                if first then
                    last = current
                end
            elseif first then
                head, current = flushrange(head,current,first,last)
                first = false
            end
            current = getnext(current)
        end
        if first then
            head, current = flushrange(head,current,first,last)
        end
        setlist(box,head)
    end

\stopluacode

% % % % % % % % % %

\setuptolerance[verytolerant,stretch]

\definefont[NotoCJK][NotoSanstc-Regular*default @ 24pt] \setupinterlinespace[40pt]

\unexpanded\def\stripe#1{\hbox orientation 0 yoffset 3pt{\strut #1}}

\setbox1000\hbox{\NotoCJK\startscript[hangul]\dorecurse{20}{通用规范汉字表 \stripe{test #1} }\stopscript}

\ctxlua{document.manipulate_one(1000)}

\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup

\page

\setbox1000\hbox{\NotoCJK\startscript[hangul]\dorecurse{20}{通用规\ruby{范}{x}汉字表 \stripe{test #1} }\stopscript}

\ctxlua{document.manipulate_one(1000)}

\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup

\page

\setupinterlinespace[40pt]

\definefontfeature
    [vertical]
    [vertical={%
        orientation=3,%
        down=.1,%
        right=.1,%
        ranges={%
            cjkcompatibility,%
            cjkcompatibilityforms,%
            cjkcompatibilityideographs,%
            cjkcompatibilityideographssupplement,%
            cjkradicalssupplement,%
          % cjkstrokes,%
            cjksymbolsandpunctuation,%
            cjkunifiedideographs,%
            cjkunifiedideographsextensiona,%
            cjkunifiedideographsextensionb,%
            cjkunifiedideographsextensionc,%
            cjkunifiedideographsextensiond,%
            cjkunifiedideographsextensione,%
            cjkunifiedideographsextensionf,%
        }%
    }]

\definefont[NotoCJKvertical][NotoSanstc-Regular*default,vertical @ 24pt]

\showglyphs

\unexpanded\def\stripe#1{\hbox orientation 0 yoffset 3pt{\strut #1}}

\setbox1000\hbox{\NotoCJKvertical\startscript[hangul]\dorecurse{20}{通用规范汉字表 \stripe{test #1} }\stopscript}

\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup

\page

\setbox1000\hbox{\NotoCJKvertical\startscript[hangul]\dorecurse{20}{通用规\ruby{范}{x}汉字表 \stripe{test #1} }\stopscript}

\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup

% \stopscript

\stoptext

[-- Attachment #4: test-directions-006.pdf --]
[-- Type: application/pdf, Size: 19235 bytes --]

[-- Attachment #5: test-directions-006.tex --]
[-- Type: text/plain, Size: 5413 bytes --]

\dontcomplain

% in font-imp-scripts, line 145, comment a few lines
%
%                 orientate = function(character)
%                     local width  = character.width or 0
%                     local height = character.height or 0
%                     local depth  = character.depth or 0
% --                     character.width       = height + depth + rightshift + rightshift
%                     character.height      = width - downshift
%                     character.depth       = shift
% --                     character.xoffset     = height + rightshift
% --                     character.yoffset     = - downshift
% --                     character.orientation = orientation
%                 end

\setuplayout[middle]

\starttext

\startluacode
    local nuts           = nodes.nuts

    local nextglyph      = nuts.traversers.glyph

    local newhlist       = nuts.pool.hlist

    local getboth        = nuts.getboth
    local setboth        = nuts.setboth
    local setlink        = nuts.setlink
    local getlist        = nuts.getlist
    local setlist        = nuts.setlist
    local setwhd         = nuts.setwhd
    local getwhd         = nuts.getwhd
    local setorientation = nuts.setorientation

    local getbox         = nuts.getbox

    local xheights       = fonts.hashes.xheights

    local function is_vertical(c)
        return c >= 0x04E00 and c <= 0x09FFF
    end

    function document.manipulate_one(boxnumber)

        local box  = getbox(boxnumber)
        local list = getlist(box)
        local all  = { }

        for n, c, f in nextglyph, list do
            if is_vertical(c) then
                all[n] = f
            end
        end

        for n, f in next, all do
            local o = .2 * xheights[f]
            local prev, next = getboth(n)
            setboth(n)
            local l = newhlist(n)
            local w, h, d = getwhd(n)
            setlink(prev,l,next)
            setwhd(l,h+d+o,w,0)
            setorientation(l,0x003,o/2,-o/2,0,h,d-o)
            if n == list then
                setlist(box,l)
            end
        end

    end

\stopluacode

\startluacode
    function document.manipulate_two(boxnumber)

        local box = tex.getbox(boxnumber)
        local n   = box.list

        local function is_vertical(c)
            return c >= 0x04E00 and c <= 0x09FFF
        end

        while n do
            if n.id == node.id("glyph") and is_vertical(n.char) then
                local o = .2 * fonts.hashes.identifiers[n.font].parameters.xheight
                local prev, next = n.prev, n.next
                n.next, n.prev = nil, nil
                local l = nodes.new("hlist")
                l.list = n
                local w, h, d = n.width, n.height, n.depth
                if prev then
                    prev.next, l.prev = l, prev
                else
                    box.list = l
                end
                if next then
                    l.next, next.prev = next, l
                end
                l.width, l.height, l.depth  = h + d + o, w, 0
                l.orientation = 0x003
--              l.xoffset, l.yoffset = o/2, -o/2
              l.hoffset, l.doffset = h, d - o
                n = next
            else
                n = n.next
            end
        end

    end

\stopluacode

% % % % % % % % % %

\unexpanded\def\stripe#1{\hbox orientation 0 yoffset 3pt{\strut #1}}

\setuptolerance[verytolerant,stretch]

\definefont[NotoCJK][NotoSanstc-Regular*default @ 24pt] \setupinterlinespace[40pt]

% % % % % % % % % %

\setbox1000\hbox{\NotoCJK\startscript[hangul]\dorecurse{20}{通用规范汉字表 \stripe{test #1} }\stopscript}
\ctxlua{document.manipulate_one(1000)}
\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup
\page

\setbox1000\hbox{\NotoCJK\startscript[hangul]\dorecurse{20}{通用规范汉字表 \stripe{test #1} }\stopscript}
\ctxlua{document.manipulate_two(1000)}
\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup
\page

\setupinterlinespace[40pt]

\definefontfeature
    [vertical]
    [vertical={%
        orientation=3,%
        down=.1,%
        right=.1,%
        ranges={%
            cjkcompatibility,%
            cjkcompatibilityforms,%
            cjkcompatibilityideographs,%
            cjkcompatibilityideographssupplement,%
            cjkradicalssupplement,%
          % cjkstrokes,%
            cjksymbolsandpunctuation,%
            cjkunifiedideographs,%
            cjkunifiedideographsextensiona,%
            cjkunifiedideographsextensionb,%
            cjkunifiedideographsextensionc,%
            cjkunifiedideographsextensiond,%
            cjkunifiedideographsextensione,%
            cjkunifiedideographsextensionf,%
        }%
    }]

\definefont[NotoCJKvertical][NotoSanstc-Regular*default,vertical @ 24pt]

\showglyphs

\unexpanded\def\stripe#1{\hbox orientation 0 yoffset 3pt{\strut #1}}

\setbox1000\hbox{\NotoCJKvertical\startscript[hangul]\dorecurse{20}{通用规范汉字表 \stripe{test #1} }\stopscript}

\ruledvbox orientation 1 to \textwidth \bgroup
    \hsize \textheight
    \unhbox1000
    \vfill
\egroup

% \stopscript

\stoptext

[-- Attachment #6: Type: text/plain, Size: 496 bytes --]

___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the Wiki!

maillist : ntg-context@ntg.nl / https://www.ntg.nl/mailman/listinfo/ntg-context
webpage  : https://www.pragma-ade.nl / http://context.aanhet.net
archive  : https://bitbucket.org/phg/context-mirror/commits/
wiki     : https://contextgarden.net
___________________________________________________________________________________

  reply	other threads:[~2022-08-21 10:00 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-15 11:02 amano.kenji via ntg-context
2022-08-15 11:43 ` Taco Hoekwater via ntg-context
2022-08-15 12:00   ` amano.kenji via ntg-context
2022-08-15 15:39     ` Wolfgang Schuster via ntg-context
2022-08-16 11:33       ` amano.kenji via ntg-context
2022-08-16 15:05         ` Wolfgang Schuster via ntg-context
2022-08-21  8:24         ` 黄复雄 via ntg-context
2022-08-21 10:00           ` Hans Hagen via ntg-context [this message]
2022-08-21 10:10           ` Wolfgang Schuster via ntg-context
2022-08-21 16:19             ` Hans Hagen via ntg-context
2022-08-22  5:21               ` 黄复雄 via ntg-context
2022-08-22  7:16                 ` Hans Hagen via ntg-context
2022-09-03 10:44                   ` 黄复雄 via ntg-context
2022-08-22  2:09             ` 黄复雄 via ntg-context
2022-08-22  4:52             ` 黄复雄 via ntg-context

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2b32e839-91a6-1b08-6c59-501ca2b5dd70@freedom.nl \
    --to=ntg-context@ntg.nl \
    --cc=amano.kenji@proton.me \
    --cc=j.hagen@freedom.nl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).