root/src/haiku_font_support.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. MessageReceived
  2. hash_string
  3. cache_font_object_data
  4. lookup_font_object_data
  5. font_object_has_chars
  6. estimate_font_ascii
  7. BFont_close
  8. BFont_metrics
  9. BFont_have_char_p
  10. BFont_have_char_block
  11. BFont_char_bounds
  12. BFont_nchar_bounds
  13. font_style_to_flags
  14. font_check_wanted_chars
  15. font_check_one_of
  16. font_check_language
  17. font_family_style_matches_p
  18. haiku_font_fill_pattern
  19. haiku_font_pattern_free
  20. BFont_find
  21. be_open_font_at_index
  22. BFont_open_pattern
  23. BFont_populate_fixed_family
  24. BFont_populate_plain_family
  25. be_list_font_families
  26. be_init_font_data
  27. be_evict_font_cache
  28. be_font_style_to_flags
  29. be_find_font_indices
  30. be_set_font_antialiasing
  31. be_send_font_settings
  32. be_listen_font_settings
  33. be_lock_font_defaults
  34. be_unlock_font_defaults
  35. be_get_font_default
  36. be_get_font_size

     1 /* Haiku window system support.  Hey, Emacs, this is -*- C++ -*-
     2    Copyright (C) 2021-2023 Free Software Foundation, Inc.
     3 
     4 This file is part of GNU Emacs.
     5 
     6 GNU Emacs is free software: you can redistribute it and/or modify
     7 it under the terms of the GNU General Public License as published by
     8 the Free Software Foundation, either version 3 of the License, or (at
     9 your option) any later version.
    10 
    11 GNU Emacs is distributed in the hope that it will be useful,
    12 but WITHOUT ANY WARRANTY; without even the implied warranty of
    13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14 GNU General Public License for more details.
    15 
    16 You should have received a copy of the GNU General Public License
    17 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    18 
    19 #include <config.h>
    20 
    21 #include <Font.h>
    22 #include <Rect.h>
    23 #include <AffineTransform.h>
    24 #include <FindDirectory.h>
    25 #include <Path.h>
    26 #include <File.h>
    27 #include <Message.h>
    28 #include <OS.h>
    29 #include <Locker.h>
    30 #include <NodeMonitor.h>
    31 #include <Looper.h>
    32 
    33 #include <cstring>
    34 #include <cmath>
    35 
    36 #include "haiku_support.h"
    37 
    38 /* Cache used during font lookup.  It contains an opened font object
    39    we can look inside, and some previously determined information.  */
    40 struct font_object_cache_bucket
    41 {
    42   struct font_object_cache_bucket *next;
    43   unsigned int hash;
    44 
    45   BFont *font_object;
    46 };
    47 
    48 static struct font_object_cache_bucket *font_object_cache[2048];
    49 
    50 /* The current global monospace family and style.  */
    51 static char *fixed_family, *fixed_style;
    52 
    53 /* The current global variable-width family and style.  */
    54 static char *default_family, *default_style;
    55 
    56 /* The sizes of each of those fonts.  */
    57 static float default_size, fixed_size;
    58 
    59 /* The locker controlling access to those variables.  */
    60 static BLocker default_locker;
    61 
    62 /* Haiku doesn't expose font language data in BFont objects.  Thus, we
    63    select a few representative characters for each supported `:lang'
    64    (currently Chinese, Korean and Japanese,) and test for those
    65    instead.  */
    66 
    67 static int language_code_points[MAX_LANGUAGE][3] =
    68   {
    69     {20154, 20754, 22996}, /* Chinese.  */
    70     {51312, 49440, 44544}, /* Korean.  */
    71     {26085, 26412, 12371}, /* Japanese.  */
    72   };
    73 
    74 static void be_send_font_settings (void);
    75 
    76 /* Looper used to track changes to system-wide font settings.  */
    77 class EmacsFontMonitorLooper : public BLooper
    78 {
    79   void
    80   MessageReceived (BMessage *msg)
    81   {
    82     int32 opcode;
    83 
    84     if (msg->what != B_NODE_MONITOR)
    85       return;
    86 
    87     if (msg->FindInt32 ("opcode", &opcode) != B_OK)
    88       return;
    89 
    90     if (opcode != B_STAT_CHANGED)
    91       return;
    92 
    93     /* Wait a little for any message to be completely written after
    94        the file's modification time changes.  */
    95     snooze (10000);
    96 
    97     /* Read and apply font settings.  */
    98     be_send_font_settings ();
    99   }
   100 };
   101 
   102 static unsigned int
   103 hash_string (const char *name_or_style)
   104 {
   105   unsigned int i;
   106 
   107   i = 3323198485ul;
   108   for (; *name_or_style; ++name_or_style)
   109     {
   110       i ^= *name_or_style;
   111       i *= 0x5bd1e995;
   112       i ^= i >> 15;
   113     }
   114   return i;
   115 }
   116 
   117 static struct font_object_cache_bucket *
   118 cache_font_object_data (const char *family, const char *style,
   119                         BFont *font_object)
   120 {
   121   uint32_t hash;
   122   struct font_object_cache_bucket *bucket, *next;
   123 
   124   hash = hash_string (family) ^ hash_string (style);
   125   bucket = font_object_cache[hash % 2048];
   126 
   127   for (next = bucket; next; next = next->next)
   128     {
   129       if (next->hash == hash)
   130         {
   131           delete next->font_object;
   132           next->font_object = font_object;
   133 
   134           return next;
   135         }
   136     }
   137 
   138   next = new struct font_object_cache_bucket;
   139   next->font_object = font_object;
   140   next->hash = hash;
   141   next->next = bucket;
   142   font_object_cache[hash % 2048] = next;
   143   return next;
   144 }
   145 
   146 static struct font_object_cache_bucket *
   147 lookup_font_object_data (const char *family, const char *style)
   148 {
   149   uint32_t hash;
   150   struct font_object_cache_bucket *bucket, *next;
   151 
   152   hash = hash_string (family) ^ hash_string (style);
   153   bucket = font_object_cache[hash % 2048];
   154 
   155   for (next = bucket; next; next = next->next)
   156     {
   157       if (next->hash == hash)
   158         return next;
   159     }
   160 
   161   return NULL;
   162 }
   163 
   164 static bool
   165 font_object_has_chars (struct font_object_cache_bucket *cached,
   166                        int *chars, int nchars, bool just_one_of)
   167 {
   168   int i;
   169 
   170   for (i = 0; i < nchars; ++i)
   171     {
   172       if (just_one_of
   173           && cached->font_object->IncludesBlock (chars[i],
   174                                                  chars[i]))
   175         return true;
   176 
   177       if (!just_one_of
   178           && !cached->font_object->IncludesBlock (chars[i],
   179                                                   chars[i]))
   180         return false;
   181     }
   182 
   183   return !just_one_of;
   184 }
   185 
   186 static void
   187 estimate_font_ascii (BFont *font, int *max_width,
   188                      int *min_width, int *avg_width)
   189 {
   190   char ch[2];
   191   bool tems[1];
   192   int total = 0;
   193   int count = 0;
   194   int min = 0;
   195   int max = 0;
   196 
   197   std::memset (ch, 0, sizeof ch);
   198   for (ch[0] = 32; ch[0] < 127; ++ch[0])
   199     {
   200       tems[0] = false;
   201       font->GetHasGlyphs (ch, 1, tems);
   202       if (tems[0])
   203         {
   204           int w = font->StringWidth (ch);
   205           ++count;
   206           total += w;
   207 
   208           if (!min || min > w)
   209             min = w;
   210           if (max < w)
   211             max = w;
   212         }
   213     }
   214 
   215   *min_width = min;
   216   *max_width = max;
   217 
   218   if (count)
   219     *avg_width = total / count;
   220   else
   221     *avg_width = 0;
   222 }
   223 
   224 void
   225 BFont_close (void *font)
   226 {
   227   if (font != (void *) be_fixed_font &&
   228       font != (void *) be_plain_font &&
   229       font != (void *) be_bold_font)
   230     delete (BFont *) font;
   231 }
   232 
   233 void
   234 BFont_metrics (void *font, int *px_size, int *min_width, int *max_width,
   235                int *avg_width, int *height, int *space_width, int *ascent,
   236                int *descent, int *underline_position, int *underline_thickness)
   237 {
   238   BFont *ft = (BFont *) font;
   239   struct font_height fheight;
   240   bool have_space_p;
   241 
   242   char atem[1];
   243   bool otem[1];
   244 
   245   ft->GetHeight (&fheight);
   246   atem[0] = ' ';
   247   otem[0] = false;
   248   ft->GetHasGlyphs (atem, 1, otem);
   249   have_space_p = otem[0];
   250 
   251   estimate_font_ascii (ft, max_width, min_width, avg_width);
   252   *ascent = std::lrint (fheight.ascent);
   253   *descent = std::lrint (fheight.descent);
   254   *height = *ascent + *descent;
   255 
   256   *space_width = have_space_p ? ft->StringWidth (" ") : 0;
   257 
   258   *px_size = std::lrint (ft->Size ());
   259   *underline_position = 0;
   260   *underline_thickness = 0;
   261 }
   262 
   263 /* Return non-null if FONT contains CHR, a Unicode code-point.  */
   264 int
   265 BFont_have_char_p (void *font, int32_t chr)
   266 {
   267   BFont *ft = (BFont *) font;
   268   return ft->IncludesBlock (chr, chr);
   269 }
   270 
   271 /* Return non-null if font contains a block from BEG to END.  */
   272 int
   273 BFont_have_char_block (void *font, int32_t beg, int32_t end)
   274 {
   275   BFont *ft = (BFont *) font;
   276   return ft->IncludesBlock (beg, end);
   277 }
   278 
   279 /* Compute bounds for MB_STR, a character in multibyte encoding, used
   280    with FONT.  The distance to move rightwards before reaching to the
   281    next character's left escapement boundary is returned in ADVANCE,
   282    the left bearing in LB, and the right bearing in RB.
   283 
   284    The left bearing is the amount of pixels from the left escapement
   285    boundary (origin) to the left-most pixel that constitutes the glyph
   286    corresponding to mb_str, and RB is the amount of pixels from the
   287    origin to the right-most pixel constituting the glyph.
   288 
   289    Both the left and right bearings are positive values measured
   290    towards the right, which means that the left bearing will only be
   291    negative if the left-most pixel is to the left of the origin.
   292 
   293    The bearing values correspond to X11 XCharStruct semantics, which
   294    is what Emacs code operates on.  Haiku itself uses a slightly
   295    different scheme, where the "left edge" is the distance from the
   296    origin to the left-most pixel, where leftwards is negative and
   297    rightwards is positive, and the "right edge" is the distance (where
   298    leftwards is similarly negative) between the right-most pixel and
   299    the right escapement boundary, which is the left escapement
   300    boundary plus the advance.  */
   301 void
   302 BFont_char_bounds (void *font, const char *mb_str, int *advance,
   303                    int *lb, int *rb)
   304 {
   305   BFont *ft = (BFont *) font;
   306   edge_info edge_info;
   307   float size, escapement;
   308   size = ft->Size ();
   309 
   310   ft->GetEdges (mb_str, 1, &edge_info);
   311   ft->GetEscapements (mb_str, 1, &escapement);
   312   *advance = std::lrint (escapement * size);
   313   *lb =  std::lrint (edge_info.left * size);
   314   *rb = *advance + std::lrint (edge_info.right * size);
   315 }
   316 
   317 /* The same, but for a variable amount of chars.  */
   318 void
   319 BFont_nchar_bounds (void *font, const char *mb_str, int *advance,
   320                     int *lb, int *rb, int32_t n)
   321 {
   322   BFont *ft = (BFont *) font;
   323   edge_info edge_info[n];
   324   float size;
   325   float escapement[n];
   326 
   327   size = ft->Size ();
   328 
   329   ft->GetEdges (mb_str, n, edge_info);
   330   ft->GetEscapements (mb_str, n, (float *) escapement);
   331 
   332   for (int32_t i = 0; i < n; ++i)
   333     {
   334       advance[i] = std::lrint (escapement[i] * size);
   335       lb[i] = advance[i] - std::lrint (edge_info[i].left * size);
   336       rb[i] = advance[i] + std::lrint (edge_info[i].right * size);
   337     }
   338 }
   339 
   340 static void
   341 font_style_to_flags (const char *style_string,
   342                      struct haiku_font_pattern *pattern)
   343 {
   344   char *style;
   345   char *token;
   346   int tok = 0;
   347 
   348   style = strdup (style_string);
   349 
   350   if (!style)
   351     return;
   352 
   353   pattern->weight = NO_WEIGHT;
   354   pattern->width = NO_WIDTH;
   355   pattern->slant = NO_SLANT;
   356 
   357   while ((token = std::strtok (!tok ? style : NULL, " ")) && tok < 3)
   358     {
   359       if (token && !strcmp (token, "Thin"))
   360         pattern->weight = HAIKU_THIN;
   361       else if (token && (!strcmp (token, "UltraLight")
   362                          || !strcmp (token, "ExtraLight")))
   363         pattern->weight = HAIKU_EXTRALIGHT;
   364       else if (token && !strcmp (token, "Light"))
   365         pattern->weight = HAIKU_LIGHT;
   366       else if (token && !strcmp (token, "SemiLight"))
   367         pattern->weight = HAIKU_SEMI_LIGHT;
   368       else if (token && !strcmp (token, "Regular"))
   369         {
   370           if (pattern->slant == NO_SLANT)
   371             pattern->slant = SLANT_REGULAR;
   372 
   373           if (pattern->width == NO_WIDTH)
   374             pattern->width = NORMAL_WIDTH;
   375 
   376           if (pattern->weight == NO_WEIGHT)
   377             pattern->weight = HAIKU_REGULAR;
   378         }
   379       else if (token && (!strcmp (token, "SemiBold")
   380                          /* Likewise, this was reported by a user.  */
   381                          || !strcmp (token, "Semibold")))
   382         pattern->weight = HAIKU_SEMI_BOLD;
   383       else if (token && !strcmp (token, "Bold"))
   384         pattern->weight = HAIKU_BOLD;
   385       else if (token && (!strcmp (token, "ExtraBold")
   386                          /* This has actually been seen in the wild.  */
   387                          || !strcmp (token, "Extrabold")
   388                          || !strcmp (token, "UltraBold")))
   389         pattern->weight = HAIKU_EXTRA_BOLD;
   390       else if (token && !strcmp (token, "Book"))
   391         pattern->weight = HAIKU_BOOK;
   392       else if (token && !strcmp (token, "Heavy"))
   393         pattern->weight = HAIKU_HEAVY;
   394       else if (token && !strcmp (token, "UltraHeavy"))
   395         pattern->weight = HAIKU_ULTRA_HEAVY;
   396       else if (token && !strcmp (token, "Black"))
   397         pattern->weight = HAIKU_BLACK;
   398       else if (token && !strcmp (token, "Medium"))
   399         pattern->weight = HAIKU_MEDIUM;
   400       else if (token && !strcmp (token, "Oblique"))
   401         pattern->slant = SLANT_OBLIQUE;
   402       else if (token && !strcmp (token, "Italic"))
   403         pattern->slant = SLANT_ITALIC;
   404       else if (token && !strcmp (token, "UltraCondensed"))
   405         pattern->width = ULTRA_CONDENSED;
   406       else if (token && !strcmp (token, "ExtraCondensed"))
   407         pattern->width = EXTRA_CONDENSED;
   408       else if (token && !strcmp (token, "Condensed"))
   409         pattern->width = CONDENSED;
   410       else if (token && !strcmp (token, "SemiCondensed"))
   411         pattern->width = SEMI_CONDENSED;
   412       else if (token && !strcmp (token, "SemiExpanded"))
   413         pattern->width = SEMI_EXPANDED;
   414       else if (token && !strcmp (token, "Expanded"))
   415         pattern->width = EXPANDED;
   416       else if (token && !strcmp (token, "ExtraExpanded"))
   417         pattern->width = EXTRA_EXPANDED;
   418       else if (token && !strcmp (token, "UltraExpanded"))
   419         pattern->width = ULTRA_EXPANDED;
   420       else
   421         {
   422           tok = 1000;
   423           break;
   424         }
   425       tok++;
   426     }
   427 
   428   if (pattern->weight != NO_WEIGHT)
   429     pattern->specified |= FSPEC_WEIGHT;
   430   if (pattern->slant != NO_SLANT)
   431     pattern->specified |= FSPEC_SLANT;
   432   if (pattern->width != NO_WIDTH)
   433     pattern->specified |= FSPEC_WIDTH;
   434 
   435   if (tok > 3)
   436     {
   437       pattern->specified &= ~FSPEC_SLANT;
   438       pattern->specified &= ~FSPEC_WEIGHT;
   439       pattern->specified &= ~FSPEC_WIDTH;
   440       pattern->specified |= FSPEC_STYLE;
   441       std::strncpy ((char *) &pattern->style,
   442                     style_string,
   443                     sizeof pattern->style - 1);
   444       pattern->style[sizeof pattern->style - 1] = '\0';
   445     }
   446 
   447   free (style);
   448 }
   449 
   450 static bool
   451 font_check_wanted_chars (struct haiku_font_pattern *pattern, font_family family,
   452                          char *style)
   453 {
   454   BFont *ft;
   455   static struct font_object_cache_bucket *cached;
   456   unicode_block wanted_block;
   457 
   458   cached = lookup_font_object_data (family, style);
   459   if (cached)
   460     ft = cached->font_object;
   461   else
   462     {
   463       ft = new BFont;
   464 
   465       if (ft->SetFamilyAndStyle (family, style) != B_OK)
   466         {
   467           delete ft;
   468           return false;
   469         }
   470 
   471       cached = cache_font_object_data (family, style, ft);
   472     }
   473 
   474   return font_object_has_chars (cached, pattern->wanted_chars,
   475                                 pattern->want_chars_len, false);
   476 }
   477 
   478 static bool
   479 font_check_one_of (struct haiku_font_pattern *pattern, font_family family,
   480                    char *style)
   481 {
   482   BFont *ft;
   483   static struct font_object_cache_bucket *cached;
   484   unicode_block wanted_block;
   485 
   486   cached = lookup_font_object_data (family, style);
   487   if (cached)
   488     ft = cached->font_object;
   489   else
   490     {
   491       ft = new BFont;
   492 
   493       if (ft->SetFamilyAndStyle (family, style) != B_OK)
   494         {
   495           delete ft;
   496           return false;
   497         }
   498 
   499       cached = cache_font_object_data (family, style, ft);
   500     }
   501 
   502   return font_object_has_chars (cached, pattern->need_one_of,
   503                                 pattern->need_one_of_len, true);
   504 }
   505 
   506 static bool
   507 font_check_language (struct haiku_font_pattern *pattern, font_family family,
   508                      char *style)
   509 {
   510   BFont *ft;
   511   static struct font_object_cache_bucket *cached;
   512 
   513   cached = lookup_font_object_data (family, style);
   514   if (cached)
   515     ft = cached->font_object;
   516   else
   517     {
   518       ft = new BFont;
   519 
   520       if (ft->SetFamilyAndStyle (family, style) != B_OK)
   521         {
   522           delete ft;
   523           return false;
   524         }
   525 
   526       cached = cache_font_object_data (family, style, ft);
   527     }
   528 
   529   if (pattern->language == MAX_LANGUAGE)
   530     return false;
   531 
   532   return font_object_has_chars (cached, language_code_points[pattern->language],
   533                                 3, false);
   534 }
   535 
   536 static bool
   537 font_family_style_matches_p (font_family family, char *style, uint32_t flags,
   538                              struct haiku_font_pattern *pattern,
   539                              int ignore_flags_p = 0)
   540 {
   541   struct haiku_font_pattern m;
   542   m.specified = 0;
   543 
   544   if (style)
   545     font_style_to_flags (style, &m);
   546 
   547   if ((pattern->specified & FSPEC_FAMILY)
   548       && strcmp ((char *) &pattern->family, family))
   549     return false;
   550 
   551   if (!ignore_flags_p && (pattern->specified & FSPEC_SPACING)
   552       && !(pattern->mono_spacing_p) != !(flags & B_IS_FIXED))
   553     return false;
   554 
   555   if (pattern->specified & FSPEC_STYLE)
   556     return style && !strcmp (style, pattern->style);
   557   /* Don't allow matching fonts with an adstyle if no style was
   558      specified in the query pattern.  */
   559   else if (m.specified & FSPEC_STYLE)
   560     return false;
   561 
   562   if ((pattern->specified & FSPEC_WEIGHT)
   563       && (pattern->weight
   564           != ((m.specified & FSPEC_WEIGHT) ? m.weight : HAIKU_REGULAR)))
   565     return false;
   566 
   567   if ((pattern->specified & FSPEC_SLANT)
   568       && (pattern->slant
   569           != (m.specified & FSPEC_SLANT
   570               ? m.slant : SLANT_REGULAR)))
   571     return false;
   572 
   573   if ((pattern->specified & FSPEC_WANTED)
   574       && !font_check_wanted_chars (pattern, family, style))
   575     return false;
   576 
   577   if ((pattern->specified & FSPEC_WIDTH)
   578       && (pattern->width
   579           != (m.specified & FSPEC_WIDTH
   580               ? m.width : NORMAL_WIDTH)))
   581     return false;
   582 
   583   if ((pattern->specified & FSPEC_NEED_ONE_OF)
   584       && !font_check_one_of (pattern, family, style))
   585     return false;
   586 
   587   if ((pattern->specified & FSPEC_LANGUAGE)
   588       && !font_check_language (pattern, family, style))
   589     return false;
   590 
   591   return true;
   592 }
   593 
   594 static void
   595 haiku_font_fill_pattern (struct haiku_font_pattern *pattern,
   596                          font_family family, char *style,
   597                          uint32_t flags)
   598 {
   599   if (style)
   600     font_style_to_flags (style, pattern);
   601 
   602   pattern->specified |= FSPEC_FAMILY;
   603   std::strncpy (pattern->family, family,
   604                 sizeof pattern->family - 1);
   605   pattern->family[sizeof pattern->family - 1] = '\0';
   606   pattern->specified |= FSPEC_SPACING;
   607   pattern->mono_spacing_p = flags & B_IS_FIXED;
   608 }
   609 
   610 /* Delete every element of the font pattern PT.  */
   611 void
   612 haiku_font_pattern_free (struct haiku_font_pattern *pt)
   613 {
   614   struct haiku_font_pattern *tem = pt;
   615   while (tem)
   616     {
   617       struct haiku_font_pattern *t = tem;
   618       tem = t->next;
   619       delete t;
   620     }
   621 }
   622 
   623 /* Find all fonts matching the font pattern PT.  */
   624 struct haiku_font_pattern *
   625 BFont_find (struct haiku_font_pattern *pt)
   626 {
   627   struct haiku_font_pattern *r = NULL;
   628   font_family name;
   629   font_style sname;
   630   uint32 flags;
   631   int sty_count, fam_count, si, fi;
   632   struct haiku_font_pattern *p, *head, *n;
   633   bool oblique_seen_p;
   634 
   635   fam_count = count_font_families ();
   636 
   637   for (fi = 0; fi < fam_count; ++fi)
   638     {
   639       if (get_font_family (fi, &name, &flags) == B_OK)
   640         {
   641           sty_count = count_font_styles (name);
   642           if (!sty_count
   643               && font_family_style_matches_p (name, NULL, flags, pt))
   644             {
   645               p = new struct haiku_font_pattern;
   646               p->specified = 0;
   647               p->oblique_seen_p = 1;
   648               haiku_font_fill_pattern (p, name, NULL, flags);
   649               p->next = r;
   650               if (p->next)
   651                 p->next->last = p;
   652               p->last = NULL;
   653               p->next_family = r;
   654               r = p;
   655 
   656               if (pt->specified & FSPEC_ANTIALIAS)
   657                 {
   658                   p->specified |= FSPEC_ANTIALIAS;
   659                   p->use_antialiasing = pt->use_antialiasing;
   660                 }
   661             }
   662           else if (sty_count)
   663             {
   664               for (si = 0; si < sty_count; ++si)
   665                 {
   666                   oblique_seen_p = 0;
   667                   head = r;
   668                   p = NULL;
   669 
   670                   if (get_font_style (name, si, &sname, &flags) == B_OK)
   671                     {
   672                       if (font_family_style_matches_p (name, (char *) &sname, flags, pt))
   673                         {
   674                           p = new struct haiku_font_pattern;
   675                           p->specified = 0;
   676                           haiku_font_fill_pattern (p, name, (char *) &sname, flags);
   677 
   678                           /* Add the indices to this font now so we
   679                              won't have to loop over each font in
   680                              order to open it later.  */
   681 
   682                           p->specified |= FSPEC_INDICES;
   683                           p->family_index = fi;
   684                           p->style_index = si;
   685 
   686                           if (pt->specified & FSPEC_ANTIALIAS)
   687                             {
   688                               p->specified |= FSPEC_ANTIALIAS;
   689                               p->use_antialiasing = pt->use_antialiasing;
   690                             }
   691 
   692                           if (p->specified & FSPEC_SLANT
   693                               && (p->slant == SLANT_OBLIQUE
   694                                   || p->slant == SLANT_ITALIC))
   695                             oblique_seen_p = 1;
   696 
   697                           p->next = r;
   698                           if (p->next)
   699                             p->next->last = p;
   700                           r = p;
   701                           p->next_family = head;
   702                         }
   703                     }
   704 
   705                   if (p)
   706                     p->last = NULL;
   707 
   708                   for (; head; head = head->last)
   709                     head->oblique_seen_p = oblique_seen_p;
   710                 }
   711             }
   712         }
   713     }
   714 
   715   /* There's a very good chance that this result will get cached if no
   716      slant is specified.  Thus, we look through each font that hasn't
   717      seen an oblique style, and add one.  */
   718 
   719   if (!(pt->specified & FSPEC_SLANT))
   720     {
   721       /* r->last is invalid from here onwards.  */
   722       for (p = r; p;)
   723         {
   724           if (!p->oblique_seen_p)
   725             {
   726               n = new haiku_font_pattern;
   727               *n = *p;
   728 
   729               n->slant = SLANT_OBLIQUE;
   730 
   731               /* Opening a font by its indices doesn't provide enough
   732                  information to synthesize the oblique font later.  */
   733               n->specified &= ~FSPEC_INDICES;
   734               p->next = n;
   735               p = p->next_family;
   736             }
   737           else
   738             p = p->next_family;
   739         }
   740     }
   741 
   742   return r;
   743 }
   744 
   745 /* Find and open a font with the family at FAMILY and the style at
   746    STYLE, and set its size to SIZE.  Value is NULL if opening the font
   747    failed.  */
   748 void *
   749 be_open_font_at_index (int family, int style, float size)
   750 {
   751   font_family family_name;
   752   font_style style_name;
   753   uint32 flags;
   754   status_t rc;
   755   BFont *font;
   756 
   757   rc = get_font_family (family, &family_name, &flags);
   758 
   759   if (rc != B_OK)
   760     return NULL;
   761 
   762   rc = get_font_style (family_name, style, &style_name, &flags);
   763 
   764   if (rc != B_OK)
   765     return NULL;
   766 
   767   font = new BFont;
   768 
   769   rc = font->SetFamilyAndStyle (family_name, style_name);
   770 
   771   if (rc != B_OK)
   772     {
   773       delete font;
   774       return NULL;
   775     }
   776 
   777   font->SetSize (size);
   778   font->SetEncoding (B_UNICODE_UTF8);
   779   font->SetSpacing (B_BITMAP_SPACING);
   780   return font;
   781 }
   782 
   783 /* Find and open a font matching the pattern PAT, which must have its
   784    family set.  */
   785 int
   786 BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size)
   787 {
   788   int sty_count, si, code;
   789   font_family name;
   790   font_style sname;
   791   BFont *ft;
   792   uint32 flags = 0;
   793   struct haiku_font_pattern copy;
   794 
   795   if (!(pat->specified & FSPEC_FAMILY))
   796     return 1;
   797 
   798   strncpy (name, pat->family, sizeof name - 1);
   799   name[sizeof name - 1] = '\0';
   800 
   801   sty_count = count_font_styles (name);
   802 
   803   if (!sty_count
   804       && font_family_style_matches_p (name, NULL, flags, pat, 1))
   805     {
   806       ft = new BFont;
   807       ft->SetSize (size);
   808       ft->SetEncoding (B_UNICODE_UTF8);
   809       ft->SetSpacing (B_BITMAP_SPACING);
   810 
   811       if (ft->SetFamilyAndStyle (name, NULL) != B_OK)
   812         {
   813           delete ft;
   814           return 1;
   815         }
   816       *font = (void *) ft;
   817       return 0;
   818     }
   819   else if (sty_count)
   820     {
   821       for (si = 0; si < sty_count; ++si)
   822         {
   823           if (get_font_style (name, si, &sname, &flags) == B_OK
   824               && font_family_style_matches_p (name, (char *) &sname,
   825                                               flags, pat))
   826             {
   827               ft = new BFont;
   828               ft->SetSize (size);
   829               ft->SetEncoding (B_UNICODE_UTF8);
   830               ft->SetSpacing (B_BITMAP_SPACING);
   831 
   832               if (ft->SetFamilyAndStyle (name, sname) != B_OK)
   833                 {
   834                   delete ft;
   835                   return 1;
   836                 }
   837 
   838               *font = (void *) ft;
   839               return 0;
   840             }
   841         }
   842     }
   843 
   844   if (pat->specified & FSPEC_SLANT && pat->slant == SLANT_OBLIQUE)
   845     {
   846       copy = *pat;
   847       copy.slant = SLANT_REGULAR;
   848       code = BFont_open_pattern (&copy, font, size);
   849 
   850       if (code)
   851         return code;
   852 
   853       ft = (BFont *) *font;
   854       /* XXX Font measurements don't respect shear.  Haiku bug?
   855          This apparently worked in BeOS.
   856          ft->SetShear (100.0); */
   857       ft->SetFace (B_ITALIC_FACE);
   858       return 0;
   859     }
   860 
   861   return 1;
   862 }
   863 
   864 /* Query the family of the default fixed font.  */
   865 void
   866 BFont_populate_fixed_family (struct haiku_font_pattern *ptn)
   867 {
   868   font_family f;
   869   font_style s;
   870   be_fixed_font->GetFamilyAndStyle (&f, &s);
   871 
   872   ptn->specified |= FSPEC_FAMILY;
   873   strncpy (ptn->family, f, sizeof ptn->family - 1);
   874   ptn->family[sizeof ptn->family - 1] = '\0';
   875 }
   876 
   877 void
   878 BFont_populate_plain_family (struct haiku_font_pattern *ptn)
   879 {
   880   font_family f;
   881   font_style s;
   882   be_plain_font->GetFamilyAndStyle (&f, &s);
   883 
   884   ptn->specified |= FSPEC_FAMILY;
   885   strncpy (ptn->family, f, sizeof ptn->family - 1);
   886   ptn->family[sizeof ptn->family - 1] = '\0';
   887 }
   888 
   889 haiku_font_family_or_style *
   890 be_list_font_families (size_t *length)
   891 {
   892   int32 families = count_font_families ();
   893   haiku_font_family_or_style *array;
   894   int32 idx;
   895   uint32 flags;
   896 
   897   array = (haiku_font_family_or_style *) malloc (sizeof *array * families);
   898 
   899   if (!array)
   900     return NULL;
   901 
   902   for (idx = 0; idx < families; ++idx)
   903     {
   904       if (get_font_family (idx, &array[idx], &flags) != B_OK)
   905         array[idx][0] = '\0';
   906     }
   907 
   908   *length = families;
   909 
   910   return array;
   911 }
   912 
   913 void
   914 be_init_font_data (void)
   915 {
   916   memset (&font_object_cache, 0, sizeof font_object_cache);
   917 }
   918 
   919 /* Free the font object cache.  This is called every 50 updates of a
   920    frame.  */
   921 void
   922 be_evict_font_cache (void)
   923 {
   924   struct font_object_cache_bucket *bucket, *last;
   925   int i;
   926 
   927   for (i = 0; i < 2048; ++i)
   928     {
   929       bucket = font_object_cache[i];
   930 
   931       while (bucket)
   932         {
   933           last = bucket;
   934           bucket = bucket->next;
   935           delete last->font_object;
   936           delete last;
   937         }
   938 
   939       font_object_cache[i] = NULL;
   940     }
   941 }
   942 
   943 void
   944 be_font_style_to_flags (const char *style, struct haiku_font_pattern *pattern)
   945 {
   946   pattern->specified = 0;
   947 
   948   font_style_to_flags (style, pattern);
   949 }
   950 
   951 int
   952 be_find_font_indices (struct haiku_font_pattern *pattern,
   953                       int *family_index, int *style_index)
   954 {
   955   int32 i, j, n_families, n_styles;
   956   font_family family;
   957   font_style style;
   958   uint32 flags;
   959 
   960   n_families = count_font_families ();
   961 
   962   for (i = 0; i < n_families; ++i)
   963     {
   964       if (get_font_family (i, &family, &flags) == B_OK)
   965         {
   966           n_styles = count_font_styles (family);
   967 
   968           for (j = 0; j < n_styles; ++j)
   969             {
   970               if (get_font_style (family, j, &style, &flags) == B_OK
   971                   && font_family_style_matches_p (family, style,
   972                                                   flags, pattern))
   973                 {
   974                   *family_index = i;
   975                   *style_index = j;
   976 
   977                   return 0;
   978                 }
   979             }
   980         }
   981     }
   982 
   983   return 1;
   984 }
   985 
   986 void
   987 be_set_font_antialiasing (void *font, bool antialias_p)
   988 {
   989   BFont *font_object;
   990 
   991   font_object = (BFont *) font;
   992   font_object->SetFlags (antialias_p
   993                          ? B_FORCE_ANTIALIASING
   994                          : B_DISABLE_ANTIALIASING);
   995 }
   996 
   997 static void
   998 be_send_font_settings (void)
   999 {
  1000   struct haiku_font_change_event rq;
  1001   BFile file;
  1002   BPath path;
  1003   status_t rc;
  1004   BMessage message;
  1005   font_family family;
  1006   font_style style;
  1007   const char *new_family, *new_style;
  1008   float new_size;
  1009 
  1010   rc = find_directory (B_USER_SETTINGS_DIRECTORY, &path);
  1011 
  1012   if (rc < B_OK)
  1013     return;
  1014 
  1015   rc = path.Append ("system/app_server/fonts");
  1016 
  1017   if (rc < B_OK)
  1018     return;
  1019 
  1020   if (file.SetTo (path.Path (), B_READ_ONLY) != B_OK)
  1021     return;
  1022 
  1023   if (message.Unflatten (&file) != B_OK)
  1024     return;
  1025 
  1026   /* Now, populate with new values.  */
  1027   if (!default_locker.Lock ())
  1028     gui_abort ("Failed to lock font data locker");
  1029 
  1030   /* Obtain default values.  */
  1031   be_fixed_font->GetFamilyAndStyle (&family, &style);
  1032   default_size = be_fixed_font->Size ();
  1033 
  1034   /* And the new values.  */
  1035   new_family = message.GetString ("fixed family", family);
  1036   new_style = message.GetString ("fixed style", style);
  1037   new_size = message.GetFloat ("fixed size", default_size);
  1038 
  1039   /* If it turns out the fixed family changed, send the new family and
  1040      style.  */
  1041 
  1042   if (!fixed_family || !fixed_style
  1043       || new_size != fixed_size
  1044       || strcmp (new_family, fixed_family)
  1045       || strcmp (new_style, fixed_style))
  1046     {
  1047       memset (&rq, 0, sizeof rq);
  1048       strncpy (rq.new_family, (char *) new_family,
  1049                sizeof rq.new_family - 1);
  1050       strncpy (rq.new_style, (char *) new_style,
  1051                sizeof rq.new_style - 1);
  1052       rq.new_size = new_size;
  1053       rq.what = FIXED_FAMILY;
  1054 
  1055       haiku_write (FONT_CHANGE_EVENT, &rq);
  1056     }
  1057 
  1058   if (fixed_family)
  1059     free (fixed_family);
  1060 
  1061   if (fixed_style)
  1062     free (fixed_style);
  1063 
  1064   fixed_family = strdup (new_family);
  1065   fixed_style = strdup (new_style);
  1066   fixed_size = new_size;
  1067 
  1068   /* Obtain default values.  */
  1069   be_plain_font->GetFamilyAndStyle (&family, &style);
  1070   default_size = be_plain_font->Size ();
  1071 
  1072   /* And the new values.  */
  1073   new_family = message.GetString ("plain family", family);
  1074   new_style = message.GetString ("plain style", style);
  1075   new_size = message.GetFloat ("plain style", default_size);
  1076 
  1077   if (!default_family || !default_style
  1078       || new_size != default_size
  1079       || strcmp (new_family, default_family)
  1080       || strcmp (new_style, default_style))
  1081     {
  1082       memset (&rq, 0, sizeof rq);
  1083       strncpy (rq.new_family, (char *) new_family,
  1084                sizeof rq.new_family - 1);
  1085       strncpy (rq.new_style, (char *) new_style,
  1086                sizeof rq.new_style - 1);
  1087       rq.new_size = new_size;
  1088       rq.what = DEFAULT_FAMILY;
  1089 
  1090       haiku_write (FONT_CHANGE_EVENT, &rq);
  1091     }
  1092 
  1093   if (default_family)
  1094     free (default_family);
  1095 
  1096   if (default_style)
  1097     free (default_style);
  1098 
  1099   default_family = strdup (new_family);
  1100   default_style = strdup (new_style);
  1101   default_size = new_size;
  1102 
  1103   default_locker.Unlock ();
  1104 }
  1105 
  1106 /* Begin listening to font settings changes, by installing a node
  1107    watcher.  This relies on the settings file already being present
  1108    and has several inherent race conditions, but users shouldn't be
  1109    changing font settings very quickly.  */
  1110 
  1111 void
  1112 be_listen_font_settings (void)
  1113 {
  1114   BPath path;
  1115   status_t rc;
  1116   BNode node;
  1117   node_ref node_ref;
  1118   EmacsFontMonitorLooper *looper;
  1119   font_family family;
  1120   font_style style;
  1121 
  1122   /* Set up initial values.  */
  1123   be_fixed_font->GetFamilyAndStyle (&family, &style);
  1124   fixed_family = strdup (family);
  1125   fixed_style = strdup (style);
  1126   fixed_size = be_fixed_font->Size ();
  1127 
  1128   be_plain_font->GetFamilyAndStyle (&family, &style);
  1129   default_family = strdup (family);
  1130   default_style = strdup (style);
  1131   default_size = be_plain_font->Size ();
  1132 
  1133   rc = find_directory (B_USER_SETTINGS_DIRECTORY, &path);
  1134 
  1135   if (rc < B_OK)
  1136     return;
  1137 
  1138   rc = path.Append ("system/app_server/fonts");
  1139 
  1140   if (rc < B_OK)
  1141     return;
  1142 
  1143   rc = node.SetTo (path.Path ());
  1144 
  1145   if (rc < B_OK)
  1146     return;
  1147 
  1148   if (node.GetNodeRef (&node_ref) < B_OK)
  1149     return;
  1150 
  1151   looper = new EmacsFontMonitorLooper;
  1152 
  1153   if (watch_node (&node_ref, B_WATCH_STAT, looper) < B_OK)
  1154     {
  1155       delete looper;
  1156       return;
  1157     }
  1158 
  1159   looper->Run ();
  1160 }
  1161 
  1162 bool
  1163 be_lock_font_defaults (void)
  1164 {
  1165   return default_locker.Lock ();
  1166 }
  1167 
  1168 void
  1169 be_unlock_font_defaults (void)
  1170 {
  1171   return default_locker.Unlock ();
  1172 }
  1173 
  1174 const char *
  1175 be_get_font_default (enum haiku_what_font what)
  1176 {
  1177   switch (what)
  1178     {
  1179     case FIXED_FAMILY:
  1180       return fixed_family;
  1181 
  1182     case FIXED_STYLE:
  1183       return fixed_style;
  1184 
  1185     case DEFAULT_FAMILY:
  1186       return default_family;
  1187 
  1188     case DEFAULT_STYLE:
  1189       return default_style;
  1190     }
  1191 
  1192   return NULL;
  1193 }
  1194 
  1195 int
  1196 be_get_font_size (enum haiku_what_font what)
  1197 {
  1198   switch (what)
  1199     {
  1200     case FIXED_FAMILY:
  1201       return fixed_size;
  1202 
  1203     case DEFAULT_FAMILY:
  1204       return default_size;
  1205 
  1206     default:
  1207       return 0;
  1208     }
  1209 }

/* [<][>][^][v][top][bottom][index][help] */