bug-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Full unicode support for back-xlib (2)


From: Kazunobu Kuriyama
Subject: Full unicode support for back-xlib (2)
Date: Thu, 17 Jul 2003 08:06:51 +0900
User-agent: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.0.0) Gecko/20020614

Hi,

Based on Fred Kiefer's suggestion, I rewrote the patches I previously sent
to bug-gnustep with the email 'Full unicode support for back-xlib'.  A few
bug fixes have also been done.

While the functionality the new patches offer remains the same as that
of the previous ones, both the organization and the performance are improved.

The main differences are:

(1) The part that was included in XGSFont.m.patch becomes two new files,
   XGFontSetFontInfo.h and XGFontSetFontInfo.m.
(2) The new module resulting from these files is used in XGContext.m.

As a result, the new module can be handled similarly to those of
XGFont.m and GSXftFontInfo.m.

To deploy the files,

   $ cp XGFontContext.m.patch /<snip>/base/Source/xlib
   $ cp XGFontSetFontInfo.m /<snip>/base/Source/xlib
   $ cp XGFontSetFontInfo.h /<snip>/base/Headers/xlib
   $ cp config.make.in.patch /<snip>/base
   $ cp configure.ac.patch /<snip>/base
   $ cp xlib.GNUmakefile.patch /<snip>/base/Source/xlib

After patching (Before it, You may need to rename the original file *.orig,
see the header of the patch files),

   $ cd /<snip>/base
   $ autoheader
   $ autoconf

to have the configure script have the new option --enable-multibyte.  Then,

   $ ./configure --enable-graphics=xlib --enable-multibyte
   $ make
   $ make install

gives you the new xlib backend that supports all characters.

When --enable-multibyte is not specified in the command line, the backend
reverts to the original implementation (i.e. that in XGFont.m) and the
resulting backend never includes the new code.  Thus the new code is
completely at your disposal.

- KK

--- XGContext.m.orig    2003-07-13 06:13:37.000000000 +0900
+++ XGContext.m 2003-07-16 15:00:00.000000000 +0900
@@ -47,6 +47,10 @@
 #include "xlib/GSXftFontInfo.h"
 #endif
 
+#ifdef USE_MULTIBYTE
+#include "xlib/XGFontSetFontInfo.h"
+#endif
+
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/keysym.h>
@@ -86,12 +90,21 @@
 #endif
   if (fontClass == Nil)
     {
+#ifndef USE_MULTIBYTE
       fontClass = [XGFontInfo class];
+#else
+      fontClass = [XGFontSetFontInfo class];
+#endif
     }
   [GSFontInfo setDefaultClass: fontClass];
   if (fontEnumerator == Nil)
     {
+#ifndef USE_MULTIBYTE
       fontEnumerator = [XGFontEnumerator class];
+#else
+      //fontEnumerator = [XGFontSetEnumerator class];
+      fontEnumerator = [XGFontEnumerator class];
+#endif
     }
   [GSFontEnumerator setDefaultClass: fontEnumerator];
 }
/*
    XGFontSetFontInfo.h

    NSFont helper for GNUstep X/GPS Backend

    Author: Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
    Date: July 2003

    This file is NOT OFFICIAL part of the GNUstep X/GPS Backend.

 */

#ifndef __XGFontSetFontInfo_h
#define __XGFontSetFontInfo_h

#include <X11/Xlib.h>
#include <AppKit/GSFontInfo.h>

// ----------------------------------------------------------------------------
//  XGFontSetEnumerator
// ----------------------------------------------------------------------------
@interface XGFontSetEnumerator : GSFontEnumerator
{
}

- (void) enumerateFontsAndFamilies;

@end // XGFontSetEnumerator : GSFontEnumerator


// ----------------------------------------------------------------------------
//  XGFontSetFontInfo
// ----------------------------------------------------------------------------
@interface XGFontSetFontInfo : GSFontInfo
{
    XFontSet    _font_set;
    XFontStruct **_fonts;
    int         _num_fonts;
}

- (id) initWithFontName: (NSString *)name
                 matrix: (const float *)matrix
             screenFont: (BOOL)screenFont;
- (void) dealloc;
- (NSSize) advancementForGlyph: (NSGlyph)glyph;
- (NSRect) boundingRectForGlyph: (NSGlyph)glyph;
- (BOOL) glyphIsEncoded: (NSGlyph)glyph;
- (NSGlyph) glyphWithName: (NSString *)glyphName;
- (void) drawGlyphs: (const NSGlyph *)glyphs
             lenght: (int)len
          onDisplay: (Display *)dpy
           drawable: (Drawable)win
               with: (GC)gc
                 at: (XPoint)xp;
- (float) widthOfGlyphs: (const NSGlyph *)glyphs
                 lenght: (int)len;
- (void) setActiveFor: (Display *)dpy
                   gc: (GC)gc;

@end // XGFontSetFontInfo : GSFontInfo


#endif // __XGFontSetFontInfo_h
/*
    XGFontSetFontInfo.m

    NSFont helper for GNUstep X/GPS Backend

    Author: Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
    Date: July 2003

    This file is NOT OFFICIAL part of the GNUstep GUI X/GPS Backend.

 */

#include "x11/XGServer.h"
#include "xlib/XGPrivate.h"
#include "xlib/XGFontSetFontInfo.h"


#define XSERVER [XGServer currentXDisplay]

typedef struct _UTF8Str {
    char    *data;
    int     size;
} UTF8Str;

#define UTF8StrData(x)  ((x)->data)
#define UTF8StrSize(x)  ((x)->size)
#define UTF8StrFree(x) \
do { \
  if ((x)->data) \
    { \
      free((x)->data); \
      (x)->data = NULL; \
      (x)->size = 0; \
    } \
} while (0)
#define UTF8StrAlloc(x, length) \
do { (x)->data = malloc(6 * (length)); } while (0)
#define UTF8StrUsable(x) ((x)->data != NULL)


// Forward declarations
static BOOL load_font_set(Display *dpy, const char *given_font_name,
                          XFontSet *font_set,
                          XFontStruct ***fonts, int *num_fonts);
static BOOL glyphs2utf8(const NSGlyph* glyphs, int length, UTF8Str* ustr);
static void char_struct_for_glyph(NSGlyph glyph, XFontSet font_set,
                                  XFontStruct **fonts, int num_fonts,
                                  XCharStruct *cs);


// ----------------------------------------------------------------------------
//  XGFontSetEnumerator
// ----------------------------------------------------------------------------
@implementation XGFontSetEnumerator : GSFontEnumerator

- (void) enumerateFontsAndFamilies
{ }

@end // XGFontSetEnumerator : GSFontEnumerator


// ----------------------------------------------------------------------------
//  XGFontSetFontInfo
// ----------------------------------------------------------------------------
@implementation XGFontSetFontInfo : GSFontInfo

- (id) initWithFontName: (NSString *)name
                 matrix: (const float *)fmatrix
             screenFont: (BOOL)screenFont
{
  Display       *dpy;
  XFontSet      font_set;
  XFontStruct   **fonts;
  XFontStruct   *base;
  int           num_fonts;

  if (screenFont)
    {
      return nil;
    }
  if (!name || [name length] == 0 || (dpy = XSERVER) == NULL)
    {
      return nil;
    }

  if (!load_font_set(dpy, [XGXFontName(name, fmatrix[0]) cString],
                     &font_set, &fonts, &num_fonts))
    {
      return nil;
    }
  base = fonts[0];

  // GSFontInfo part
  [super init];
  ASSIGN(fontName, name);
  ASSIGN(familyName, XGFontFamily(dpy, fonts[0]));
  memcpy(matrix, fmatrix, sizeof(matrix));
  italicAngle           = 0;
  underlinePosition     = 0;
  underlineThickness    = 0;
  capHeight             = 0;
  xHeight               = 0;
  descender             = -base->descent;
  ascender              = base->ascent;
  maximumAdvancement    =
    NSMakeSize(base->max_bounds.width,
               base->max_bounds.ascent + base->max_bounds.descent);
  minimumAdvancement    = NSMakeSize(0, 0);
  ASSIGN(encodingScheme, @"");
  mostCompatibleStringEncoding = NSASCIIStringEncoding;
  fontBBox              =
    NSMakeRect(base->min_bounds.lbearing,
               -base->max_bounds.ascent,
               base->max_bounds.rbearing - base->max_bounds.lbearing,
               base->max_bounds.ascent + base->max_bounds.descent);
  isFixedPitch          = XGFontIsFixedPitch(dpy, base);
  isBaseFont            = NO;
  weight                = XGWeightOfFont(dpy, base);
  traits                = XGTraitsOfFont(dpy, base);

  // XGFontSetFontInfo part
  _font_set = font_set;
  _fonts = fonts;
  _num_fonts = num_fonts;

  return self;
}

- (void) dealloc
{
  if (_font_set)
    {
      XFreeFontSet(XSERVER, _font_set);
      _font_set = NULL;
    }
}

- (NSSize) advancementForGlyph: (NSGlyph)glyph
{
  XCharStruct cs;

  char_struct_for_glyph(glyph, _font_set, _fonts, _num_fonts, &cs);
  if (cs.width == 0)
    {
      cs.width = _fonts[0]->max_bounds.width;
    }
  return NSMakeSize((float)cs.width, 0);
}

- (NSRect) boundingRectForGlyph: (NSGlyph)glyph
{
  XCharStruct cs;

  char_struct_for_glyph(glyph, _font_set, _fonts, _num_fonts, &cs);
  if (cs.width == 0)
    {
      return fontBBox;
    }
  return NSMakeRect((float)cs.lbearing, (float)-cs.descent,
                    (float)(cs.rbearing - cs.lbearing),
                    (float)(cs.ascent + cs.descent));
}

- (BOOL) glyphIsEncoded: (NSGlyph)glyph
{
  XCharStruct cs;
  XCharStruct zero;

  char_struct_for_glyph(glyph, _font_set, _fonts, _num_fonts, &cs);
  memset(&zero, 0, sizeof(XCharStruct));
  return (BOOL)memcmp(&cs, &zero, sizeof(XCharStruct));
}

- (NSGlyph) glyphWithName: (NSString *)glyphName
{
  KeySym k;

  k = XStringToKeysym([glyphName cString]);
  if (k == NoSymbol)
    return 0;
  else
    return (NSGlyph)k;
}

- (void) drawGlyphs: (const NSGlyph *)glyphs
             lenght: (int)len
          onDisplay: (Display *)dpy
           drawable: (Drawable)win
               with: (GC)gc
                 at: (XPoint)xp
{
  UTF8Str ustr;

  if (glyphs2utf8(glyphs, len, &ustr))
    {
      Xutf8DrawString(dpy, win, _font_set, gc, xp.x, xp.y,
                      UTF8StrData(&ustr), UTF8StrSize(&ustr));
      UTF8StrFree(&ustr);
    }
}

- (float) widthOfGlyphs: (const NSGlyph *)glyphs
                 lenght: (int)len
{
  UTF8Str   ustr;
  float     val;

  if (glyphs2utf8(glyphs, len, &ustr))
    {
      XRectangle logical;

      Xutf8TextExtents(_font_set, UTF8StrData(&ustr), UTF8StrSize(&ustr),
                       NULL, &logical);
      UTF8StrFree(&ustr);
      val = logical.width;
    }
  else
    {
      val = 0.0;
    }
  return val;
}

- (void) setActiveFor: (Display *)dpy
                   gc: (GC)gc
{
  // Do nothing.
}

@end // XGFontSetFontInfo : GSFontInfo


// ----------------------------------------------------------------------------
//  Static Functions
// ----------------------------------------------------------------------------
static BOOL
load_font_set(Display *dpy, const char *given_font_name,
              XFontSet *font_set, XFontStruct ***fonts, int *num_fonts)
{
  int   i;
  char  xlfd[256];
  int   xlfd_num_elms;
  BOOL  has_add_style;
  char  *xlfd_elms[14];
  char  base_font_name[256];

  char  **missing_charsets;
  int   num_missing_charsets;
  char  *def_string;

  char          **font_names;
  int           num_font_names;
  XFontStruct   **font_structs;

  if (!dpy || !given_font_name)
    {
      return NO;
    }

  strcpy(xlfd, given_font_name);

  xlfd_num_elms = 14;
  has_add_style = YES;
  if (strstr(xlfd, "--"))
    {
      --xlfd_num_elms;
      has_add_style = NO;
    }

  i = 0;
  xlfd_elms[i++] = strtok(xlfd, "-");
  while (i < xlfd_num_elms)
    {
      xlfd_elms[i++] = strtok(NULL, "-");
    }

  // To let the X server determine a font set automatically, some elements
  // of the XLFD should be replaced with the wild card.
  if (has_add_style)
    {
      sprintf(base_font_name,
              "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
              xlfd_elms[0],     // foundry
              "*",              // family
              xlfd_elms[2],     // weight
              xlfd_elms[3],     // slant
              xlfd_elms[4],     // set width
              xlfd_elms[5],     // add style
              xlfd_elms[6],     // pixel size
              xlfd_elms[7],     // point size
              xlfd_elms[8],     // resolutionX
              xlfd_elms[9],     // resolutionY
              "*",              // spacing
              xlfd_elms[11],    // avg width
              "*",              // registry
              "*"               // encoding
             );
    }
  else
    {
      sprintf(base_font_name,
              "-%s-%s-%s-%s-%s--%s-%s-%s-%s-%s-%s-%s-%s",
              xlfd_elms[0],     // foundry
              "*",              // family
              xlfd_elms[2],     // weight
              xlfd_elms[3],     // slant
              xlfd_elms[4],     // set width
              xlfd_elms[5],     // pixel size
              xlfd_elms[6],     // point size
              xlfd_elms[7],     // resolutionX
              xlfd_elms[8],     // resolutionY
              "*",              // spacing
              xlfd_elms[10],    // avg width
              "*",              // registry
              "*"               // encoding
             );
    }

  // N.B. def_string is owned by the X server: Don't release it.
  missing_charsets      = NULL;
  num_missing_charsets  = 0;
  def_string            = NULL;
  *font_set             = NULL;
  *font_set = XCreateFontSet(dpy, base_font_name,
                             &missing_charsets,
                             &num_missing_charsets,
                             &def_string);
  if (!*font_set)
    {
      NSLog(@"XGFontSetFontInfo: Can't create a font set\n");
      return NO;
    }
  if (num_missing_charsets > 0)
    {
      for (i = 0; i < num_missing_charsets; ++i)
        {
          NSLog(@"XGFontSetFontInfo: Charset %s is not available\n",
                missing_charsets[i]);
        }
      XFreeStringList(missing_charsets);
      missing_charsets = NULL;
      num_missing_charsets = 0;
    }

  // N.B. font_structs and font_names are owned by the X server: Don't
  // release them.
  num_font_names    = 0;
  font_structs      = NULL;
  font_names        = NULL;
  num_font_names = XFontsOfFontSet(*font_set, &font_structs, &font_names);
  if (!num_font_names)
    {
      NSLog(@"XGFontSetFontInfo: "
            "Can't get any information from the font set\n");
      return NO;
    }

  *fonts = font_structs;
  *num_fonts = num_font_names;

  return YES;
}

// N.B. Use UTF8StrFree() to release the space pointed to by 'ustr'.
static BOOL
glyphs2utf8(const NSGlyph* glyphs, int length, UTF8Str* ustr)
{
  int       i;
  NSGlyph   *g;
  NSGlyph   *end;
  char      *p;

  if (!glyphs || !length)
    {
      return NO;
    }

  UTF8StrAlloc(ustr, length);
  if (!UTF8StrUsable(ustr))
    {
      return NO;
    }

  p = UTF8StrData(ustr);
  i = 0;
  for (g = (NSGlyph *)glyphs, end = (NSGlyph *)glyphs + length; g < end; ++g)
    {
      if (*g < 0x00000080)
        {
          p[i++] = *g;
        }
      else if (*g < 0x00000800)
        {
          p[i++] = 0xc0 | ((*g >>  6) & 0x1f);
          p[i++] = 0x80 | ( *g        & 0x3f);
        }
      else if (*g < 0x00010000)
        {
          p[i++] = 0xe0 | ((*g >> 12) & 0x0f);
          p[i++] = 0x80 | ((*g >>  6) & 0x3f);
          p[i++] = 0x80 | ( *g        & 0x3f);
        }
      else if (*g < 0x00200000)
        {
          p[i++] = 0xf0 | ((*g >> 18) & 0x07);
          p[i++] = 0x80 | ((*g >> 12) & 0x3f);
          p[i++] = 0x80 | ((*g >>  6) & 0x3f);
          p[i++] = 0x80 | ( *g        & 0x3f);
        }
      else if (*g < 0x04000000)
        {
          p[i++] = 0xf8 | ((*g >> 24) & 0x03);
          p[i++] = 0x80 | ((*g >> 18) & 0x3f);
          p[i++] = 0x80 | ((*g >> 12) & 0x3f);
          p[i++] = 0x80 | ((*g >>  6) & 0x3f);
          p[i++] = 0x80 | ( *g        & 0x3f);
        }
      else if (*g < 0x80000000)
        {
          p[i++] = 0xfc | ((*g >> 30) & 0x01);
          p[i++] = 0x80 | ((*g >> 24) & 0x3f);
          p[i++] = 0x80 | ((*g >> 18) & 0x3f);
          p[i++] = 0x80 | ((*g >> 12) & 0x3f);
          p[i++] = 0x80 | ((*g >>  6) & 0x3f);
          p[i++] = 0x80 | ( *g        & 0x3f);
        }
      else
        {
          // Out of range
          UTF8StrFree(ustr);
          return NO;
        }
    }
  UTF8StrSize(ustr) = i;

  return YES;
}

static void
char_struct_for_glyph(NSGlyph glyph, XFontSet font_set,
                      XFontStruct **fonts, int num_fonts,
                      XCharStruct *cs)
{
  UTF8Str utf8char;

  if (glyphs2utf8(&glyph, 1, &utf8char))
    {
      XRectangle    ink, logical;
      int           num_chars;

      Xutf8TextPerCharExtents(font_set,
                              UTF8StrData(&utf8char), UTF8StrSize(&utf8char),
                              &ink, &logical, 1, &num_chars, NULL, NULL);
      UTF8StrFree(&utf8char);

      if (num_chars != 1)
        {
          memset(cs, 0, sizeof(XCharStruct));
          return;
        }

      cs->lbearing      = 0;
      cs->rbearing      = 0;
      cs->width         = logical.width;
      cs->ascent        = fonts[0]->max_bounds.ascent;
      cs->descent       = fonts[0]->max_bounds.descent;
      cs->attributes    = 0;
    }
  else
    {
      memset(cs, 0, sizeof(XCharStruct));
    }
}
--- config.make.in.orig 2003-07-13 06:13:36.000000000 +0900
+++ config.make.in      2003-07-16 14:26:27.000000000 +0900
@@ -4,6 +4,7 @@
 
 WITH_WRASTER=@WITH_WRASTER@
 WITH_XFT=@WITH_XFT@
+WITH_MULTIBYTE=@WITH_MULTIBYTE@
 
 GRAPHIC_LIBS=@GRAPHIC_LIBS@
 GRAPHIC_CFLAGS=@GRAPHIC_CFLAGS@
--- configure.ac.orig   2003-07-13 06:13:36.000000000 +0900
+++ configure.ac        2003-07-16 14:23:01.000000000 +0900
@@ -203,6 +203,43 @@
 AC_SUBST(WITH_XFT)
 
 #--------------------------------------------------------------------
+# Yet another extended font support & UTF8 support for back-xlib
+#
+# - This section is relevent only if --enable-graphics=xlib.
+# - Defines USE_MULTIBYTE in config.h.in.
+# - USE_MULTIBYTE is to set to 1 in config.h if --enable-multibyte is
+#   given and X11/Xlib.h defines X_HAVE_UTF8_STRING.
+# - Otherwise, this section does nothing. 
+#--------------------------------------------------------------------
+AC_ARG_ENABLE(multibyte,
+    [  --enable-multibyte      Enable multibyte char support for xlib 
graphics],
+    enable_multibyte=yes, enable_multibyte=no)
+
+WITH_MULTIBYTE=no
+if test "x$enable_multibyte" = "xyes"; then
+    AC_MSG_CHECKING([for XFree86 >= 4.0.2])
+    enable_multibyte_save_header=${CPPFLAGS}
+    CPPFLAGS="${GRAPHIC_CFLAGS} ${GRAPHIC_LFLAGS} ${CPPFLAGS}"
+    AC_EGREP_CPP(yes,
+                [
+                   #include <X11/Xlib.h>
+                   #ifdef X_HAVE_UTF8_STRING
+                   yes
+                   #endif
+                ], have_x_have_utf8_string=yes, have_x_have_utf8_string=no)
+    AC_MSG_RESULT([$have_x_have_utf8_string])
+    if test "x$have_x_have_utf8_string" = "xyes"; then
+       AC_DEFINE([USE_MULTIBYTE], 1,
+                 [Define to enable multibyte char support for xlib graphics])
+       WITH_MULTIBYTE=yes
+    else
+       AC_MSG_WARN([You need XFree86 >= 4.0.2 for --enable-multibyte])
+    fi
+    CPPFLAGS="${enable_multibyte_save_header}"
+fi
+AC_SUBST(WITH_MULTIBYTE)
+
+#--------------------------------------------------------------------
 # GLX support
 #--------------------------------------------------------------------
 WITH_GLX=no
--- GNUmakefile.orig    2003-07-13 06:13:37.000000000 +0900
+++ GNUmakefile 2003-07-16 17:58:36.000000000 +0900
@@ -38,7 +38,6 @@
 xlib_OBJC_FILES = \
 XGBitmap.m \
 XGCommonFont.m \
-XGFont.m \
 XGFontManager.m \
 XGContext.m \
 XGGState.m \
@@ -49,6 +48,12 @@
 xlib_OBJC_FILES += GSXftFontInfo.m
 endif
 
+ifeq ($(WITH_MULTIBYTE),yes)
+xlib_OBJC_FILES += XGFontSetFontInfo.m
+else
+xlib_OBJC_FILES += XGFont.m
+endif
+
 xlib_HEADER_FILES_DIR = ../../Headers/xlib
 xlib_HEADER_FILES_INSTALL_DIR = gnustep/xlib
 
2003-07-17  Kazunobu Kuriyama  <kazunobu.kuriyama@nifty.com>

        * Source/xlib/XGFontSetFontInfo.m: New file.
        * Headers/xlib/XGFontSetFontInfo.h: New file.
        * Source/xlib/XGContext.m: Use XGFontSetFontInfo, depending on the
        value of WITH_MULTIBYTE.
        * configure.ac: Add the new option --enable-multibyte.
        * config.make.in: Add the configurable constant WITH_MULTIBYTE.
        * Source/xlib/GNUmakefile: Compilation switch based on
        WITH_MULTIBYTE.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]