emacs-devel
[Top][All Lists]
Advanced

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

Re: font-backend


From: YAMAMOTO Mitsuharu
Subject: Re: font-backend
Date: Sat, 23 Feb 2008 11:44:32 +0900
User-agent: Wanderlust/2.14.0 (Africa) SEMI/1.14.6 (Maruoka) FLIM/1.14.8 (Shijō) APEL/10.6 Emacs/23.0.50 (sparc-sun-solaris2.8) MULE/5.0 (SAKAKI)

>>>>> On Sat, 23 Feb 2008 02:23:26 +0000, Jason Rumney <address@hidden> said:

>> I'm developing a font backend driver using Core Text, which is a
>> new framework available from Mac OS X 10.5.  It was slower than
>> Emacs 22 first, but now it shows good performance with caching the
>> results of metrics calculations.

> Yes, it is definitely the metrics calculations that are slowing
> things down on Windows too. I added some code to cache the metrics
> for ASCII characters some time ago, but the problem remains for
> buffers containing many non-ASCII characters.

But it still does get_frame_dc and SelectObject even for the
ASCII-only case.  I think this can be deferred until cache miss
happens.

FWIW, below shows what the Core Text font backend is doing on the
metrics caching.  I assume the height of a valid metrics value is
always nonnegative.


                                     YAMAMOTO Mitsuharu
                                address@hidden

/* The actual structure for Mac Core Text font that can be casted to
   struct font.  */

struct ctfont_info
{
  struct font font;
  CTFontRef ctfont;
  unsigned synthetic_italic_p : 1;
  unsigned synthetic_bold_p : 1;
  short metrics_nrows;
  struct font_metrics **metrics;
};

#define METRICS_NCOLS_PER_ROW   (128)

enum metrics_status
  {
    METRICS_INVALID = -1,  /* metrics entry is invalid */
    METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
  };

#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
#define METRICS_SET_STATUS(metrics, status) \
  ((metrics)->ascent = 0, (metrics)->descent = (status))

static int
ctfont_glyph_extents (font, glyph, metrics)
     struct font *font;
     CGGlyph glyph;
     struct font_metrics *metrics;
{
  struct ctfont_info *ctfont_info = (struct ctfont_info *) font;
  CTFontRef ctfont = ctfont_info->ctfont;
  int row, col;
  struct font_metrics *cache;
  int width;

  row = glyph / METRICS_NCOLS_PER_ROW;
  col = glyph % METRICS_NCOLS_PER_ROW;
  if (row >= ctfont_info->metrics_nrows)
    {
      ctfont_info->metrics =
        xrealloc (ctfont_info->metrics,
                 sizeof (struct font_metrics *) * (row + 1));
      bzero (ctfont_info->metrics + ctfont_info->metrics_nrows,
             (sizeof (struct font_metrics *)
              * (row + 1 - ctfont_info->metrics_nrows)));
      ctfont_info->metrics_nrows = row + 1;
    }
  if (ctfont_info->metrics[row] == NULL)
    {
      struct font_metrics *new;
      int i;

      new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
      for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
        METRICS_SET_STATUS (new + i, METRICS_INVALID);
      ctfont_info->metrics[row] = new;
    }
  cache = ctfont_info->metrics[row] + col;

  if (METRICS_STATUS (cache) == METRICS_INVALID)
    {
      cache->width =
        CTFontGetAdvancesForGlyphs (ctfont, kCTFontDefaultOrientation,
                                    &glyph, NULL, 1) + 0.5;
      METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
    }
  width = cache->width;

  if (metrics)
    {
      if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
        {
          CGRect bounds;

          bounds = CTFontGetBoundingRectsForGlyphs (ctfont,
                                                    kCTFontDefaultOrientation,
                                                    &glyph, NULL, 1);
          if (ctfont_info->synthetic_italic_p)
            bounds = CGRectApplyAffineTransform (bounds, synthetic_italic_atfm);
          if (ctfont_info->synthetic_bold_p)
            {
              CGFloat d = - synthetic_bold_factor * CTFontGetSize (ctfont) / 2;

              bounds = CGRectInset (bounds, d, d);
            }
          bounds = CGRectIntegral (bounds);
          cache->lbearing = CGRectGetMinX (bounds);
          cache->rbearing = CGRectGetMaxX (bounds);
          cache->width = width;
          cache->ascent = CGRectGetMaxY (bounds);
          cache->descent = -CGRectGetMinY (bounds);
        }
      *metrics = *cache;
    }

  return width;
}

static int
ctfont_text_extents (font, code, nglyphs, metrics)
     struct font *font;
     unsigned *code;
     int nglyphs;
     struct font_metrics *metrics;
{
  int width, i;

  BLOCK_INPUT;
  width = ctfont_glyph_extents (font, code[0], metrics);
  for (i = 1; i < nglyphs; i++)
    {
      struct font_metrics m;
      int w = ctfont_glyph_extents (font, code[i], metrics ? &m : NULL);

      if (metrics)
        {
          if (width + m.lbearing < metrics->lbearing)
            metrics->lbearing = width + m.lbearing;
          if (width + m.rbearing > metrics->rbearing)
            metrics->rbearing = width + m.rbearing;
          if (m.ascent > metrics->ascent)
            metrics->ascent = m.ascent;
          if (m.descent > metrics->descent)
            metrics->descent = m.descent;
        }
      width += w;
    }
  UNBLOCK_INPUT;

  if (metrics)
    metrics->width = width;

  return width;
}




reply via email to

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