all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: JunJie Nan <nanjunjie@gmail.com>
To: emacs-devel@gnu.org
Subject: Re: A patch for enforcing double-width CJK character display
Date: Mon, 28 Apr 2014 13:35:03 +0800	[thread overview]
Message-ID: <CA+Gegu_J9EFD6WhiXvA8C+5EA2BwvpRD0Y_HLe_Lgb35kBkM0g@mail.gmail.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 254 bytes --]

Do not know why the patch is still not installed, although from the
discussion thread nobody oppose it indeed.

Below is an updated version based on current stream. It still works well.


-- 
Cheers
Jun Jie Nan
  ∧ ∧︵
 ミ^ō^ミ灬)~

[-- Attachment #1.2: Type: text/html, Size: 345 bytes --]

[-- Attachment #2: emacs_src_xftfont.patch --]
[-- Type: text/x-patch, Size: 7057 bytes --]

diff --git a/src/xftfont.c b/src/xftfont.c
index 18c180f..2020b4f 100644
--- a/src/xftfont.c
+++ b/src/xftfont.c
@@ -60,6 +60,8 @@ struct xftfont_info
   Display *display;
   XftFont *xftfont;
   unsigned x_display_id;
+  struct frame *frame; /* hold frame ptr, cjk double width fix need it */
+  int is_cjk; /* Flag to tell if it is CJK font or not. */
 };
 
 /* Structure pointed by (struct face *)->extra  */
@@ -133,6 +135,83 @@ xftfont_get_colors (struct frame *f, struct face *face, GC gc,
 }
 
 
+/* Check whether the font contains CJK Ideograph 'number one', 0x4E00,
+   It should be ok for Chinese/Japanese font.
+   Or font contains Korean script syllable 'Ka',0xAC00,
+   because Korean fonts may not have any Chinese characters at all.
+   codes from xterm.*/
+static int
+xftfont_is_cjk_font(struct xftfont_info *xftfont_info)
+{
+  if(XftCharExists(xftfont_info->display, xftfont_info->xftfont, 0x4E00) ||
+      XftCharExists(xftfont_info->display, xftfont_info->xftfont, 0xAC00))
+    return 1;
+  return 0; 
+}
+
+/* Get the padding according to default monospace font width */
+static int
+xftfont_get_cjk_padding(int default_width, int char_width, int *half_width_cjk)
+{
+  int padding = 0;
+  if(half_width_cjk)
+    *half_width_cjk = 0;
+
+  if( default_width == 0 || /* something wrong */
+      default_width == -1 || /* default font is not monospace */
+      char_width == default_width) /* already good */
+    return 0;
+  if( char_width < default_width) { 
+    /* almost impossible, but we can handle it */
+    padding = default_width - char_width;
+    if(half_width_cjk)
+        *half_width_cjk = 1;
+  } else /* get the padding, all cjk symbols is DOUBLE width */
+    padding = default_width * 2 - char_width;
+  /* 1, Some old CJK pcf fonts may bigger than 2*default_width.
+     2, User may set a very big font size for script HAN manually.
+     Keep it unchanged, NOT adjust default font width. */
+  return (padding > 0 && padding < default_width) ? padding : 0;                  
+}
+
+/* Get the font width of monospace font. 
+   Something wrong: return 0;
+   Default is not monospace: return -1;
+   Otherwise: return monospace font width; */
+static int 
+xftfont_get_default_width(struct xftfont_info *xftfont_info)
+{
+  Lisp_Object font_object;
+  double request_pixel_size;
+  struct frame *frame = xftfont_info->frame;
+  FcPattern * pattern = xftfont_info->xftfont->pattern;
+  int id = lookup_basic_face (frame, DEFAULT_FACE_ID);
+  struct face *face = FACE_FROM_ID (frame, id);
+  if(!face && !face->font)
+    return 0;
+  XSETFONT (font_object, face->font);
+  /* default font is not monospace */
+  if (XINT(AREF (font_object, FONT_SPACING_INDEX)) != FONT_SPACING_MONO)
+    return -1;
+  if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &request_pixel_size) != FcResultMatch)
+    return 0;
+  /* the font of minibuf/modeline never changed when rescaling.
+     it's a little bit difficult to determine where the xftfont draw to.
+     for example, when use mule/leim to input some CJK text.
+     it will draw on the selected frame and minibuf(candidate string).
+     by the way, the 'int' conversion should be ok. */ 
+  if(FRAME_FONT(frame)->pixel_size == (int)request_pixel_size) 
+    return FRAME_FONT(frame)->space_width;
+  /* User may set a fixed font size for script han manually,
+     the font will not rescale when issue rescaling,
+     should not ajust the width offset and avoid to make it too wide.
+     its alignment will be wrong, but let's respect user settings.*/
+  if(face->font->pixel_size != (int)request_pixel_size)
+    return FRAME_FONT(frame)->space_width;
+  /* otherwise return the current font width */
+  return face->font->space_width;
+}
+
 struct font_driver xftfont_driver;
 
 static Lisp_Object
@@ -420,6 +499,15 @@ xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
       font->average_width = (font->space_width + extents.xOff) / 95;
     }
+
+  /* to fix CJK double width alignment issue.
+     pass FRAME_PTR to every xftfont_info structure,
+     we can not get it in "xftfont_text_extents". */
+  xftfont_info->frame = f;
+  /* mark it is CJK font or not when font opened,
+     avoid calling "xftfont_is_cjk_font" many times. */
+  xftfont_info->is_cjk = xftfont_is_cjk_font(xftfont_info);
+
   unblock_input ();
 
   font->ascent = xftfont->ascent;
@@ -588,19 +676,29 @@ xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   XGlyphInfo extents;
 
+  int cjk_padding = 0;
+  int l_padding = 0;
+  int r_padding = 0;
+
   block_input ();
   XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
 		   &extents);
+  if(xftfont_info->is_cjk)
+    cjk_padding = xftfont_get_cjk_padding(xftfont_get_default_width(xftfont_info), extents.xOff, NULL);
+  /* cjk_padding may equals to 0, then all is zero, still ok */
+  l_padding = cjk_padding >> 1; /* get half */
+  r_padding = cjk_padding - l_padding; /* may not divided by 2 exactly */ 
+
   unblock_input ();
   if (metrics)
     {
-      metrics->lbearing = - extents.x;
-      metrics->rbearing = - extents.x + extents.width;
-      metrics->width = extents.xOff;
+      metrics->lbearing = - extents.x - l_padding;
+      metrics->rbearing = - extents.x + extents.width + r_padding;
+      metrics->width = extents.xOff + cjk_padding;
       metrics->ascent = extents.y;
       metrics->descent = extents.height - extents.y;
     }
-  return extents.xOff;
+  return extents.xOff + cjk_padding;
 }
 
 static XftDraw *
@@ -658,9 +756,28 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
     for (i = 0; i < len; i++)
       XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
 		     x + i, y, code + i, 1);
-  else
-    XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
-		   x, y, code, len);
+  else {
+      int default_width = xftfont_get_default_width(xftfont_info);
+      if(!xftfont_info->is_cjk || default_width == -1) /* not cjk or default not monospace */ 
+        XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont, x, y, code, len);
+      else /* draw CJK glyphs one by one and adjust the offset */
+         for (i = 0; i < len; i++) {
+           int cjk_padding = 0;
+           int offset = 0;
+           int half_width_cjk = 0;
+           XGlyphInfo extents;
+           XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code+i, 1,
+                            &extents);
+           cjk_padding = xftfont_get_cjk_padding(default_width,extents.xOff, &half_width_cjk);
+           if(cjk_padding) 
+             offset = default_width * i * (half_width_cjk ? 1 : 2) + (cjk_padding>>1);
+           else
+             offset = extents.xOff * i; 
+           XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
+                            x+offset, y, code+i, 1);
+         }
+  }
+
   unblock_input ();
 
   return len;

             reply	other threads:[~2014-04-28  5:35 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-28  5:35 JunJie Nan [this message]
2014-04-29  5:39 ` A patch for enforcing double-width CJK character display Stefan Monnier
2014-04-29  6:36   ` Jan D.
2014-04-29  8:16   ` Thien-Thi Nguyen
2014-04-29 20:41 ` Liang Wang
  -- strict thread matches above, loose matches on Subject: below --
2014-10-04  3:26 Feng Shu
2014-04-30  2:00 Hui Liu
2014-04-30 17:08 ` Liang Wang
     [not found] <4F85A138.6090900@i-soft.com.cn>
2012-04-11 15:48 ` Kan-Ru Chen
2012-04-11 16:16   ` 黄建忠
2012-04-12  8:56     ` 黄建忠
2012-04-12  9:53       ` Eli Zaretskii
2012-04-12 11:18         ` 黄建忠
2012-04-12 14:27           ` Eli Zaretskii
2012-04-12 17:56             ` 黄建忠
2012-04-12 20:33               ` Stefan Monnier
     [not found]                 ` <4F8782C8.2030005@i-soft.com.cn>
2012-04-13 11:42                   ` 黄建忠
2012-04-13 12:03                     ` 黄建忠
2012-04-13 13:27                   ` Stefan Monnier
2012-04-15  5:10                     ` Miles Bader
2012-04-15 13:27                       ` 黄建忠
2012-04-15 16:08                       ` William Xu
2012-04-15 22:19                         ` Miles Bader
2012-04-16  0:51                           ` 黄建忠
2012-04-16  5:27                             ` Miles Bader
2012-04-16  5:40                               ` 黄建忠
2012-04-16  6:37                                 ` 黄建忠
2012-04-16  9:21                                   ` 黄建忠
2012-04-17  2:16                                     ` 黄建忠
2012-04-17  0:13                                   ` Miles Bader
2012-04-17  0:39                                     ` Miles Bader
2012-04-17  2:00                                       ` 黄建忠
2012-04-17  2:30                                         ` Miles Bader
2012-04-17  3:00                                           ` 黄建忠
2012-04-17  4:08                                             ` Miles Bader
2012-04-17  4:56                                               ` Werner LEMBERG
2012-04-17  5:02                                                 ` 黄建忠
2012-04-17  6:33                                                   ` Miles Bader
2012-04-17  7:03                                                   ` Werner LEMBERG
2012-04-17  5:52                                                 ` Miles Bader
2012-04-17  6:10                                                   ` 黄建忠
2012-04-17  7:02                                                     ` Miles Bader
2012-04-17  8:06                                                       ` Werner LEMBERG
2012-04-17  8:25                                                         ` Miles Bader
2012-04-17  9:06                                                           ` Werner LEMBERG
2012-04-17  8:51                                                       ` 黄建忠
2012-04-17  6:45                                                   ` Werner LEMBERG
2012-04-17  9:07                                       ` James Cloos
2012-04-17  9:27                                         ` 黄建忠
2012-04-17  1:47                                     ` 黄建忠
2012-04-18  6:54                               ` Kenichi Handa
2012-04-18  8:13                                 ` 黄建忠
2012-04-18 13:58                                 ` Miles Bader

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=CA+Gegu_J9EFD6WhiXvA8C+5EA2BwvpRD0Y_HLe_Lgb35kBkM0g@mail.gmail.com \
    --to=nanjunjie@gmail.com \
    --cc=emacs-devel@gnu.org \
    /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.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.