Ticket #2457: multiLanguage.diff

File multiLanguage.diff, 9.6 KB (added by sanderd17, 10 years ago)
  • source/gui/GUItext.cpp

    diff --git a/source/gui/GUItext.cpp b/source/gui/GUItext.cpp
    index d832884..fcb6adf 100644
    a b GUI text  
    3030
    3131static const wchar_t TagStart = '[';
    3232static const wchar_t TagEnd   = ']';
     33// List of word demlimitor bounds
     34// The list contains ranges of word delimitors. The odd indexed chars are the start
     35// of a range, the even are the end of a range. The list must be sorted in INCREASING ORDER
     36static const int NUM_WORD_DELIMITORS = 4*2;
     37static const u16 WordDelimitors[NUM_WORD_DELIMITORS] = {
     38    ' '   , ' ',    // spaces
     39    '-'   , '-',    // hyphens
     40    0x3000, 0x3002, // ideographic symbols (maybe this range should be wider)
     41    0x4E00, 0x9FFF  // characters in the Chinese unicode block
     42// TODO add unicode blocks of other languages that don't use spaces
     43};
    3344
    3445void CGUIString::SFeedback::Reset()
    3546{
    void CGUIString::SetValue(const CStrW& str)  
    513524    // Add a delimiter at start and at end, it helps when
    514525    //  processing later, because we don't have make exceptions for
    515526    //  those cases.
    516     // We'll sort later.
    517527    m_Words.push_back(0);
    518     m_Words.push_back((int)m_RawString.length());
    519 
    520     // Space: ' '
    521     for (position=0, curpos=0;;position = curpos+1)
    522     {
    523         // Find the next word-delimiter.
    524         long dl = m_RawString.Find(position, ' ');
    525 
    526         if (dl == -1)
    527             break;
    528 
    529         curpos = dl;
    530         m_Words.push_back((int)dl+1);
    531     }
    532 
    533     // Dash: '-'
    534     for (position=0, curpos=0;;position = curpos+1)
    535     {
    536         // Find the next word-delimiter.
    537         long dl = m_RawString.Find(position, '-');
    538 
    539         if (dl == -1)
    540             break;
    541 
    542         curpos = dl;
    543         m_Words.push_back((int)dl+1);
    544     }
    545528
    546     // New Line: '\n'
    547     for (position=0, curpos=0;;position = curpos+1)
     529    // Add word boundaries in increasing order
     530    for (u32 i = 0; i < m_RawString.length(); ++i)
    548531    {
    549         // Find the next word-delimiter.
    550         long dl = m_RawString.Find(position, '\n');
    551 
    552         if (dl == -1)
    553             break;
    554 
    555         curpos = dl;
    556 
    557         // Add before and
    558         m_Words.push_back((int)dl);
    559         m_Words.push_back((int)dl+1);
     532        wchar_t c = m_RawString[i];
     533        if (c == '\n')
     534        {
     535            m_Words.push_back((int)i);
     536            m_Words.push_back((int)i+1);
     537            continue;
     538        }
     539        for (int n = 0; n < NUM_WORD_DELIMITORS; n += 2)
     540        {
     541            if (c <= WordDelimitors[n+1])
     542            {
     543                if (c >= WordDelimitors[n])
     544                    m_Words.push_back((int)i+1);
     545                // assume the WordDelimitors list is stored in increasing order
     546                break;
     547            }
     548        }
    560549    }
    561550
    562     sort(m_Words.begin(), m_Words.end());
     551    m_Words.push_back((int)m_RawString.length());
    563552
    564553    // Remove duplicates (only if larger than 2)
    565554    if (m_Words.size() > 2)
  • source/tools/fontbuilder2/fontbuilder.py

    diff --git a/source/tools/fontbuilder2/fontbuilder.py b/source/tools/fontbuilder2/fontbuilder.py
    index efffc9c..ef8b05c 100644
    a b import Packer  
    77
    88# Representation of a rendered glyph
    99class Glyph(object):
    10     def __init__(self, ctx, renderstyle, char, idx):
     10    def __init__(self, ctx, renderstyle, char, idx, face, size):
    1111        self.renderstyle = renderstyle
    1212        self.char = char
    1313        self.idx = idx
     14        self.face = face
     15        self.size = size
    1416        self.glyph = (idx, 0, 0)
    1517
     18        if not ctx.get_font_face() == self.face:
     19            ctx.set_font_face(self.face)
     20            ctx.set_font_size(self.size)
    1621        extents = ctx.glyph_extents([self.glyph])
    1722
    1823        self.xadvance = round(extents[4])
    class Glyph(object):  
    5257        self.pos = packer.Pack(self.w, self.h)
    5358
    5459    def render(self, ctx):
     60        if not ctx.get_font_face() == self.face:
     61            ctx.set_font_face(self.face)
     62            ctx.set_font_size(self.size)
    5563        ctx.save()
    5664        ctx.translate(self.x0, self.y0)
    5765        ctx.translate(self.pos.x, self.pos.y)
    def load_char_list(filename):  
    8189    return set(chars)
    8290
    8391# Construct a Cairo context and surface for rendering text with the given parameters
    84 def setup_context(width, height, face, size, renderstyle):
     92def setup_context(width, height, renderstyle):
    8593    format = (cairo.FORMAT_ARGB32 if "colour" in renderstyle else cairo.FORMAT_A8)
    8694    surface = cairo.ImageSurface(format, width, height)
    8795    ctx = cairo.Context(surface)
    88     ctx.set_font_face(face)
    89     ctx.set_font_size(size)
    9096    ctx.set_line_join(cairo.LINE_JOIN_ROUND)
    9197    return ctx, surface
    9298
    93 def generate_font(chars, outname, ttf, loadopts, size, renderstyle):
     99def generate_font(outname, ttfNames, loadopts, size, renderstyle, dsizes):
    94100
    95     (face, indexes) = FontLoader.create_cairo_font_face_for_file(ttf, 0, loadopts)
     101    faceList = []
     102    indexList = []
     103    for i in range(len(ttfNames)):
     104        (face, indices) = FontLoader.create_cairo_font_face_for_file("../../../binaries/data/tools/fontbuilder/fonts/%s" % ttfNames[i], 0, loadopts)
     105        faceList.append(face)
     106        if not ttfNames[i] in dsizes:
     107            dsizes[ttfNames[i]] = 0
     108        indexList.append(indices)
    96109
    97     (ctx, _) = setup_context(1, 1, face, size, renderstyle)
     110    (ctx, _) = setup_context(1, 1, renderstyle)
    98111
    99     (ascent, descent, linespacing, _, _) = ctx.font_extents()
     112    # TODO this gets the line height from the default font
     113    # while entire texts can be in the fallback font
     114    ctx.set_font_face(faceList[0]);
     115    ctx.set_font_size(size + dsizes[ttfNames[0]])
     116    (_, _, linespacing, _, _) = ctx.font_extents()
    100117
    101118    # Estimate the 'average' height of text, for vertical center alignment
    102     charheight = round(ctx.glyph_extents([(indexes("I"), 0.0, 0.0)])[3])
     119    charheight = round(ctx.glyph_extents([(indexList[0]("I"), 0.0, 0.0)])[3])
    103120
    104121    # Translate all the characters into glyphs
    105122    # (This is inefficient if multiple characters have the same glyph)
    106123    glyphs = []
    107     for c in chars:
    108         idx = indexes(c)
    109         if ord(c) == 0xFFFD and idx == 0: # use "?" if the missing-glyph glyph is missing
    110             idx = indexes("?")
    111         if idx:
    112             glyphs.append(Glyph(ctx, renderstyle, c, idx))
     124    #for c in chars:
     125    for c in range(0x20, 0xFFFD):
     126        for i in range(len(indexList)):
     127            idx = indexList[i](unichr(c))
     128            if c == 0xFFFD and idx == 0: # use "?" if the missing-glyph glyph is missing
     129                idx = indexList[i]("?")
     130            if idx:
     131                glyphs.append(Glyph(ctx, renderstyle, unichr(c), idx, faceList[i], size + dsizes[ttfNames[i]]))
     132                break
    113133
    114134    # Sort by decreasing height (tie-break on decreasing width)
    115135    glyphs.sort(key = lambda g: (-g.h, -g.w))
    116136
    117137    # Try various sizes to pack the glyphs into
    118138    sizes = []
    119     for h in [32, 64, 128, 256, 512, 1024]:
    120         for w in [32, 64, 128, 256, 512, 1024]:
    121             sizes.append((w, h))
     139    for h in [32, 64, 128, 256, 512, 1024, 2048, 4096]:
     140        sizes.append((h, h))
     141        sizes.append((h*2, h))
    122142    sizes.sort(key = lambda (w, h): (w*h, max(w, h))) # prefer smaller and squarer
    123143
    124144    for w, h in sizes:
    125145        try:
    126             #packer = Packer.DumbRectanglePacker(w, h)
    127             packer = Packer.CygonRectanglePacker(w, h)
     146            packer = Packer.DumbRectanglePacker(w, h)
     147            #packer = Packer.CygonRectanglePacker(w, h)
    128148            for g in glyphs:
    129149                g.pack(packer)
    130150        except Packer.OutOfSpaceError:
    131151            continue
    132152
    133         ctx, surface = setup_context(w, h, face, size, renderstyle)
     153        ctx, surface = setup_context(w, h, renderstyle)
    134154        for g in glyphs:
    135             g.render(ctx)
     155            g.render(ctx)
    136156        surface.write_to_png("%s.png" % outname)
    137157
    138158        # Output the .fnt file with all the glyph positions etc
    def generate_font(chars, outname, ttf, loadopts, size, renderstyle):  
    143163        fnt.write("%d\n" % len(glyphs))
    144164        fnt.write("%d\n" % linespacing)
    145165        fnt.write("%d\n" % charheight)
    146         glyphs.sort(key = lambda g: ord(g.char))
     166        # sorting unneeded, as glyphs are added in increasing order
     167        #glyphs.sort(key = lambda g: ord(g.char))
    147168        for g in glyphs:
    148169            x0 = g.x0
    149170            y0 = g.y0
    stroked1 = { "colour": True, "stroke": [((0, 0, 0, 1), 2.0), ((0, 0, 0, 1), 2.0)  
    168189stroked2 = { "colour": True, "stroke": [((0, 0, 0, 1), 2.0)], "fill": [(1, 1, 1, 1), (1, 1, 1, 1)] }
    169190stroked3 = { "colour": True, "stroke": [((0, 0, 0, 1), 2.5)], "fill": [(1, 1, 1, 1), (1, 1, 1, 1)] }
    170191
    171 chars = load_char_list("charset.txt")
     192DejaVuSansMono = (["DejaVuSansMono.ttf","FreeMono.ttf", "HanaMinA.ttf"], FontLoader.FT_LOAD_DEFAULT)
     193DejaVuSans = (["DejaVuSans.ttf","FreeSans.ttf", "HanaMinA.ttf"], FontLoader.FT_LOAD_DEFAULT)
     194PagellaRegular = (["texgyrepagella-regular.otf","FreeSerif.ttf", "HanaMinA.ttf"], FontLoader.FT_LOAD_NO_HINTING)
     195PagellaBold = (["texgyrepagella-bold.otf","FreeSerifBold.ttf", "HanaMinA.ttf"], FontLoader.FT_LOAD_NO_HINTING)
    172196
    173 DejaVuSansMono = ("DejaVuSansMono.ttf", FontLoader.FT_LOAD_DEFAULT)
    174 DejaVuSans = ("DejaVuSans.ttf", FontLoader.FT_LOAD_DEFAULT)
    175 PagellaRegular = ("texgyrepagella-regular.otf", FontLoader.FT_LOAD_NO_HINTING)
    176 PagellaBold = ("texgyrepagella-bold.otf", FontLoader.FT_LOAD_NO_HINTING)
     197# Define the size differences used to render different fallback fonts
     198dsizes = {'HanaMinA.ttf': 2}
    177199
    178200fonts = (
    179201    ("mono-10", DejaVuSansMono, 10, filled),
    fonts = (  
    201223    ("serif-stroke-16", PagellaRegular, 16, stroked2),
    202224)
    203225
    204 for (name, (fontname, loadopts), size, style) in fonts:
     226for (name, (fontnames, loadopts), size, style) in fonts:
    205227    print "%s..." % name
    206     generate_font(chars, "../../../binaries/data/mods/public/fonts/%s" % name, "../../../binaries/data/tools/fontbuilder/fonts/%s" % fontname, loadopts, size, style)
     228    generate_font("../../../binaries/data/mods/public/fonts/%s" % name, fontnames, loadopts, size, style, dsizes)