int win_draw_text(win_t *win, XftDraw *d, const XftColor *color, int x, int y, char *text, int len, int w) { int err, tw = 0; char *t, *next; uint32_t rune; XftFont *f; FcCharSet *fccharset; XGlyphInfo ext; for (t = text; t - text < len; t = next) { next = utf8_decode(t, &rune, &err); if (XftCharExists(win->env.dpy, font, rune)) { f = font; } else { /* fallback font */ fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, rune); f = XftFontOpen(win->env.dpy, win->env.scr, FC_CHARSET, FcTypeCharSet, fccharset, FC_SCALABLE, FcTypeBool, FcTrue, FC_SIZE, FcTypeDouble, fontsize, NULL); FcCharSetDestroy(fccharset); } XftTextExtentsUtf8(win->env.dpy, f, (XftChar8*)t, next - t, &ext); tw += ext.xOff; if (tw <= w) { XftDrawStringUtf8(d, color, f, x, y, (XftChar8*)t, next - t); x += ext.xOff; } if (f != font) XftFontClose(win->env.dpy, f); } return tw; }
FcPattern* BC_Resources::find_similar_font(FT_ULong char_code, FcPattern *oldfont) { FcPattern *pat, *font; FcFontSet *fs; FcObjectSet *os; FcCharSet *fcs; FcChar8 *file; double dval; int ival; // Do not search control codes if(char_code < ' ') return 0; fontconfig_lock.lock("BC_Resources::find_similar_font"); pat = FcPatternCreate(); os = FcObjectSetBuild(FC_FILE, FC_CHARSET, FC_SCALABLE, FC_FAMILY, FC_SLANT, FC_WEIGHT, FC_WIDTH, (char *)0); FcPatternAddBool(pat, FC_SCALABLE, true); fcs = FcCharSetCreate(); if(FcCharSetAddChar(fcs, char_code)) FcPatternAddCharSet(pat, FC_CHARSET, fcs); FcCharSetDestroy(fcs); for(int i = 0; i < LEN_FCPROP; i++) { if(FcPatternGetInteger(oldfont, fc_properties[i], 0, &ival) == FcResultMatch) FcPatternAddInteger(pat, fc_properties[i], ival); } fs = FcFontList(0, pat, os); for(int i = LEN_FCPROP - 1; i >= 0 && fs->nfont == 0; i--) { FcFontSetDestroy(fs); FcPatternDel(pat, fc_properties[i]); fs = FcFontList(0, pat, os); } FcPatternDestroy(pat); FcObjectSetDestroy(os); pat = 0; for (int i = 0; i < fs->nfont; i++) { font = fs->fonts[i]; if(FcPatternGetCharSet(font, FC_CHARSET, 0, &fcs) == FcResultMatch) { if(FcCharSetHasChar(fcs, char_code)) { pat = FcPatternDuplicate(font); break; } } } FcFontSetDestroy(fs); fontconfig_lock.unlock(); return pat; }
gchar* find_font_with_property (FcConfig* fontconfig, const gchar* characters, const gchar* property) { FcPattern* pattern; FcCharSet* character_set; FcObjectSet* font_properties; FcFontSet* fonts; FcPattern* font; FcChar8* path; gchar* result; gchar* remaining_characters; gunichar character; if (fontconfig == NULL) { g_warning("Font config not loaded."); return NULL; } result = NULL; pattern = FcPatternCreate (); character_set = FcCharSetCreate (); remaining_characters = (gchar*) characters; while (TRUE) { character = g_utf8_get_char (remaining_characters); if (character == '\0') { break; } FcCharSetAddChar(character_set, character); remaining_characters = g_utf8_next_char (remaining_characters); } FcPatternAddCharSet (pattern, FC_CHARSET, character_set); FcCharSetDestroy (character_set); FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); font_properties = FcObjectSetBuild (property, NULL); fonts = FcFontList (fontconfig, pattern, font_properties); if (fonts && fonts->nfont > 0) { font = fonts->fonts[0]; if (FcPatternGetString(font, property, 0, &path) == FcResultMatch) { result = g_strdup ((gchar*) path); } } if (fonts) { FcFontSetDestroy(fonts); } if (pattern) { FcPatternDestroy(pattern); } return result; }
static String getFontFamilyForCharacters(const UChar* characters, size_t numCharacters) { FcCharSet* cset = FcCharSetCreate(); for (size_t i = 0; i < numCharacters; ++i) { if (U16_IS_SURROGATE(characters[i]) && U16_IS_SURROGATE_LEAD(characters[i]) && i != numCharacters - 1 && U16_IS_TRAIL(characters[i + 1])) { if (FcCharSetAddChar(cset, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1])) == FcFalse) return String(); i++; } else if (FcCharSetAddChar(cset, characters[i]) == FcFalse) return String(); } FcPattern *pattern = FcPatternCreate(); FcPatternAddCharSet(pattern, FC_CHARSET, cset); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcPattern *match = FcFontMatch(0, pattern, &result); FcChar8 *filename; if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) { FcCharSetDestroy(cset); FcPatternDestroy(match); FcPatternDestroy(pattern); return String(); } FcChar8* family; if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { FcCharSetDestroy(cset); FcPatternDestroy(match); FcPatternDestroy(pattern); const char* charFamily = reinterpret_cast<char*>(family); return String(charFamily); } FcPatternDestroy(match); FcCharSetDestroy(cset); FcPatternDestroy(pattern); return String(); }
static const FcCharSet * scan (FILE *f, char *file, FcCharSetFreezer *freezer) { FcCharSet *c = 0; const FcCharSet *n; int start, end, ucs4; char line[1024]; int lineno = 0; while (get_line (f, line, &lineno)) { if (!strncmp (line, "include", 7)) { file = strchr (line, ' '); if (!file) fatal (line, lineno, "invalid syntax, expected: include filename"); while (isspace(*file)) file++; f = scanopen (file); if (!f) fatal (file, 0, "can't open"); n = scan (f, file, freezer); fclose (f); return n; } if (strchr (line, '-')) { if (sscanf (line, "%x-%x", &start, &end) != 2) fatal (file, lineno, "parse error"); } else { if (sscanf (line, "%x", &start) != 1) fatal (file, lineno, "parse error"); end = start; } if (!c) c = FcCharSetCreate (); for (ucs4 = start; ucs4 <= end; ucs4++) { if (!FcCharSetAddChar (c, ucs4)) fatal (file, lineno, "out of memory"); } } n = FcCharSetFreeze (freezer, c); FcCharSetDestroy (c); return n; }
static FcCharSet * scan (FILE *f, char *file) { FcCharSet *c = 0; FcCharSet *n; int start, end, ucs4; char line[1024]; int lineno = 0; while (get_line (f, line, &lineno)) { if (!strncmp (line, "include", 7)) { file = strchr (line, ' '); while (*file == ' ') file++; end = strlen (file); if (file[end-1] == '\n') file[end-1] = '\0'; f = fopen (file, "r"); if (!f) fatal (file, 0, "can't open"); c = scan (f, file); fclose (f); return c; } if (strchr (line, '-')) { if (sscanf (line, "%x-%x", &start, &end) != 2) fatal (file, lineno, "parse error"); } else { if (sscanf (line, "%x", &start) != 1) fatal (file, lineno, "parse error"); end = start; } if (!c) c = FcCharSetCreate (); for (ucs4 = start; ucs4 <= end; ucs4++) { if (!FcCharSetAddChar (c, ucs4)) fatal (file, lineno, "out of memory"); } } n = FcCharSetFreeze (c); FcCharSetDestroy (c); return n; }
FcCharSet * mozilla_decoder_get_charset (PangoFcDecoder *decoder, PangoFcFont *fcfont) { MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder); if (priv->charset) return priv->charset; // First time this has been accessed. Populate the charset. priv->charset = FcCharSetCreate(); if (!gCharsetManager) { CallGetService(kCharsetConverterManagerCID, &gCharsetManager); } nsCOMPtr<nsIUnicodeEncoder> encoder; nsCOMPtr<nsICharRepresentable> represent; if (!gCharsetManager) goto end; gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder)); if (!encoder) goto end; encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?'); priv->uEncoder = encoder; represent = do_QueryInterface(encoder); if (!represent) goto end; PRUint32 map[UCS2_MAP_LEN]; memset(map, 0, sizeof(map)); represent->FillInfo(map); for (int i = 0; i < NUM_UNICODE_CHARS; i++) { if (IS_REPRESENTABLE(map, i)) FcCharSetAddChar(priv->charset, i); } end: return priv->charset; }
static RefPtr<FcPattern> createFontConfigPatternForCharacters(const UChar* characters, int bufferLength) { RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate()); FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate()); UTF16UChar32Iterator iterator(characters, bufferLength); UChar32 character = iterator.next(); while (character != iterator.end()) { FcCharSetAddChar(fontConfigCharSet.get(), character); character = iterator.next(); } FcPatternAddCharSet(pattern.get(), FC_CHARSET, fontConfigCharSet.get()); FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue); FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern); FcDefaultSubstitute(pattern.get()); return pattern; }
FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int bufferLength) { FcPattern* pattern = FcPatternCreate(); FcCharSet* fontConfigCharSet = FcCharSetCreate(); UTF16UChar32Iterator iterator(characters, bufferLength); UChar32 character = iterator.next(); while (character != iterator.end()) { FcCharSetAddChar(fontConfigCharSet, character); character = iterator.next(); } FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet); FcCharSetDestroy(fontConfigCharSet); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); return pattern; }
static void gui_init_xft(void) { int i; /* 釋放原有的字型 */ if (gui->xftfonts) { for (i=0 ; i < gui->num_fonts ; i++) { XftFontClose(gui->display, gui->xftfonts[i]); } free(gui->xftfonts); } gui->num_fonts = 0; gui->xftfonts = NULL; /* 釋放缺字表 */ if (gui->missing_chars) { FcCharSetDestroy(gui->missing_chars); } gui->missing_chars = FcCharSetCreate(); /* */ for (i = 0 ; i < MAX_COLORS ; i++) { XftColorFree(gui->display, gui->visual, gui->colormap, &gui->colors[i]); XftColorAllocName(gui->display, gui->visual, gui->colormap, oxim_get_config(colors[i].key_id), &gui->colors[colors[i].color_idx]); } /* 紀錄預設字型大小 */ unsigned int default_fontsize = atoi(oxim_get_config(DefaultFontSize)); if (default_fontsize < 12 || default_fontsize > 48) default_fontsize = 16; gui->default_fontsize = default_fontsize; }
FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int length) { FcPattern* pattern = FcPatternCreate(); FcCharSet* fontConfigCharSet = FcCharSetCreate(); for (int i = 0; i < length; ++i) { if (U16_IS_SURROGATE(characters[i]) && U16_IS_SURROGATE_LEAD(characters[i]) && i != length - 1 && U16_IS_TRAIL(characters[i + 1])) { FcCharSetAddChar(fontConfigCharSet, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1])); i++; } else FcCharSetAddChar(fontConfigCharSet, characters[i]); } FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet); FcCharSetDestroy(fontConfigCharSet); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); return pattern; }
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) { FcCharSet* cset = FcCharSetCreate(); for (int i = 0; i < length; ++i) FcCharSetAddChar(cset, characters[i]); FcPattern* pattern = FcPatternCreate(); FcValue fcvalue; fcvalue.type = FcTypeCharSet; fcvalue.u.c = cset; FcPatternAdd(pattern, FC_CHARSET, fcvalue, 0); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcPattern* match = FcFontMatch(0, pattern, &result); FcPatternDestroy(pattern); SimpleFontData* ret = 0; if (match) { FcChar8* family; if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { AtomicString fontFamily(reinterpret_cast<char*>(family)); ret = getCachedFontData(getCachedFontPlatformData(font.fontDescription(), fontFamily, false)); } FcPatternDestroy(match); } FcCharSetDestroy(cset); return ret; }
/* Constructor of the object : it allocates memory and initializes the member * of the new object. * The user must give the FcPattern of the font or the master (which may be NULL * in which case the character map will be empty). */ __GLCcharMap* __glcCharMapCreate(const __GLCmaster* inMaster, const __GLCcontext* inContext) { __GLCcharMap* This = NULL; assert(inContext); This = (__GLCcharMap*)__glcMalloc(sizeof(__GLCcharMap)); if (!This) { __glcRaiseError(GLC_RESOURCE_ERROR); return NULL; } memset(This, 0, sizeof(__GLCcharMap)); This->charSet = FcCharSetCreate(); if (!This->charSet) { __glcRaiseError(GLC_RESOURCE_ERROR); __glcFree(This); return NULL; } if (inMaster) { FcCharSet* charSet = NULL; FcFontSet* fontSet = NULL; int i = 0; FcObjectSet* objectSet = NULL; FcPattern* pattern = FcPatternCreate(); if (!pattern) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_SPACING, FC_OUTLINE, FC_CHARSET, NULL); if (!objectSet) { __glcRaiseError(GLC_RESOURCE_ERROR); FcPatternDestroy(pattern); FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } fontSet = FcFontList(inContext->config, pattern, objectSet); FcObjectSetDestroy(objectSet); FcPatternDestroy(pattern); if (!fontSet) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } for (i = 0; i < fontSet->nfont; i++) { FcChar8* family = NULL; int fixed = 0; FcChar8* foundry = NULL; FcBool outline = FcFalse; FcBool equal = FcFalse; #ifdef DEBUGMODE FcResult result = FcResultMatch; result = FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline); assert(result != FcResultTypeMismatch); #else FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline); #endif /* Check whether the glyphs are outlines */ if (!outline) continue; #ifdef DEBUGMODE result = FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family); assert(result != FcResultTypeMismatch); result = FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry); assert(result != FcResultTypeMismatch); result = FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed); assert(result != FcResultTypeMismatch); #else FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family); FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry); FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed); #endif if (foundry) pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family, FC_FOUNDRY, FcTypeString, foundry, FC_SPACING, FcTypeInteger, fixed, NULL); else pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family, FC_SPACING, FcTypeInteger, fixed, NULL); if (!pattern) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); FcFontSetDestroy(fontSet); __glcFree(This); return NULL; } equal = FcPatternEqual(pattern, inMaster->pattern); FcPatternDestroy(pattern); if (equal) { FcCharSet* newCharSet = NULL; #ifdef DEBUGMODE result = FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &charSet); assert(result != FcResultTypeMismatch); #else FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &charSet); #endif newCharSet = FcCharSetUnion(This->charSet, charSet); if (!newCharSet) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); FcFontSetDestroy(fontSet); __glcFree(This); return NULL; } FcCharSetDestroy(This->charSet); This->charSet = newCharSet; } } FcFontSetDestroy(fontSet); } /* The array 'map' will contain the actual character map */ This->map = __glcArrayCreate(sizeof(__GLCcharMapElement)); if (!This->map) { FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } return This; }
bool FontConfigDirect::Match(std::string* result_family, unsigned* result_filefaceid, bool filefaceid_valid, unsigned filefaceid, const std::string& family, const void* data, size_t characters_bytes, bool* is_bold, bool* is_italic) { if (family.length() > kMaxFontFamilyLength) return false; SkAutoMutexAcquire ac(mutex_); // Given |family|, |is_bold| and |is_italic| but not |data|, the result will // be a function of these three parameters, and thus eligible for caching. // This is the fast path for |SkTypeface::CreateFromName()|. bool eligible_for_cache = !family.empty() && is_bold && is_italic && !data; if (eligible_for_cache) { int style = (*is_bold ? SkTypeface::kBold : 0 ) | (*is_italic ? SkTypeface::kItalic : 0); FontMatchKey key = FontMatchKey(family, style); const std::map<FontMatchKey, FontMatch>::const_iterator i = font_match_cache_.find(key); if (i != font_match_cache_.end()) { *is_bold = i->second.is_bold; *is_italic = i->second.is_italic; if (result_family) *result_family = i->second.family; if (result_filefaceid) *result_filefaceid = i->second.filefaceid; return true; } } FcPattern* pattern = FcPatternCreate(); if (filefaceid_valid) { const std::map<unsigned, std::string>::const_iterator i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid)); if (i == fileid_to_filename_.end()) { FcPatternDestroy(pattern); return false; } int face_index = filefaceid & 0xfu; FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(i->second.c_str())); // face_index is added only when family is empty because it is not // necessary to uniquiely identify a font if both file and // family are given. if (family.empty()) FcPatternAddInteger(pattern, FC_INDEX, face_index); } if (!family.empty()) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) family.c_str()); } FcCharSet* charset = NULL; if (data) { charset = FcCharSetCreate(); const uint16_t* chars = (const uint16_t*) data; size_t num_chars = characters_bytes / 2; for (size_t i = 0; i < num_chars; ++i) { if (U16_IS_SURROGATE(chars[i]) && U16_IS_SURROGATE_LEAD(chars[i]) && i != num_chars - 1 && U16_IS_TRAIL(chars[i + 1])) { FcCharSetAddChar(charset, U16_GET_SUPPLEMENTARY(chars[i], chars[i+1])); i++; } else { FcCharSetAddChar(charset, chars[i]); } } FcPatternAddCharSet(pattern, FC_CHARSET, charset); FcCharSetDestroy(charset); // pattern now owns it. } FcPatternAddInteger(pattern, FC_WEIGHT, is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); FcPatternAddInteger(pattern, FC_SLANT, is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Font matching: // CSS often specifies a fallback list of families: // font-family: a, b, c, serif; // However, fontconfig will always do its best to find *a* font when asked // for something so we need a way to tell if the match which it has found is // "good enough" for us. Otherwise, we can return NULL which gets piped up // and lets WebKit know to try the next CSS family name. However, fontconfig // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we // wish to support that. // // Thus, if a specific family is requested we set @family_requested. Then we // record two strings: the family name after config processing and the // family name after resolving. If the two are equal, it's a good match. // // So consider the case where a user has mapped Arial to Helvetica in their // config. // requested family: "Arial" // post_config_family: "Helvetica" // post_match_family: "Helvetica" // -> good match // // and for a missing font: // requested family: "Monaco" // post_config_family: "Monaco" // post_match_family: "Times New Roman" // -> BAD match // // However, we special-case fallback fonts; see IsFallbackFontAllowed(). FcChar8* post_config_family; FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family); FcResult result; FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); if (!font_set) { FcPatternDestroy(pattern); return false; } FcPattern* match = MatchFont(font_set, post_config_family, family); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return false; } FcPatternDestroy(pattern); FcChar8* c_filename; if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } int face_index; if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FontMatch font_match; if (filefaceid_valid) { font_match.filefaceid = filefaceid; } else { unsigned out_fileid; const std::string filename(reinterpret_cast<char*>(c_filename)); const std::map<std::string, unsigned>::const_iterator i = filename_to_fileid_.find(filename); if (i == filename_to_fileid_.end()) { out_fileid = next_file_id_++; filename_to_fileid_[filename] = out_fileid; fileid_to_filename_[out_fileid] = filename; } else { out_fileid = i->second; } // fileid stored in filename_to_fileid_ and fileid_to_filename_ is // unique only up to the font file. We have to encode face_index for // the out param. font_match.filefaceid = FileIdAndFaceIndexToFileFaceId(out_fileid, face_index); } bool success = GetFontProperties(match, &font_match.family, &font_match.is_bold, &font_match.is_italic); FcFontSetDestroy(font_set); if (success) { // If eligible, cache the result of the matching. if (eligible_for_cache) { int style = (*is_bold ? SkTypeface::kBold : 0 ) | (*is_italic ? SkTypeface::kItalic : 0); font_match_cache_[FontMatchKey(family, style)] = font_match; } if (result_family) *result_family = font_match.family; if (result_filefaceid) *result_filefaceid = font_match.filefaceid; if (is_bold) *is_bold = font_match.is_bold; if (is_italic) *is_italic = font_match.is_italic; } return success; }
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text) { char buf[1024]; int tx, ty, th; Extnts tex; XftDraw *d = NULL; Fnt *curfont, *nextfont; size_t i, len; int utf8strlen, utf8charlen, render; long utf8codepoint = 0; const char *utf8str; FcCharSet *fccharset; FcPattern *fcpattern; FcPattern *match; XftResult result; int charexists = 0; if (!drw->scheme || !drw->fontcount) return 0; if (!(render = x || y || w || h)) { w = ~w; } else { XSetForeground(drw->dpy, drw->gc, drw->scheme->bg->pix); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); } curfont = drw->fonts[0]; while (1) { utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); for (i = 0; i < drw->fontcount; i++) { charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint); if (charexists) { if (drw->fonts[i] == curfont) { utf8strlen += utf8charlen; text += utf8charlen; } else { nextfont = drw->fonts[i]; } break; } } if (!charexists || (nextfont && nextfont != curfont)) break; else charexists = 0; } if (utf8strlen) { drw_font_getexts(curfont, utf8str, utf8strlen, &tex); /* shorten text if necessary */ for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--) drw_font_getexts(curfont, utf8str, len, &tex); if (len) { memcpy(buf, utf8str, len); buf[len] = '\0'; if (len < utf8strlen) for (i = len; i && i > len - 3; buf[--i] = '.'); if (render) { th = curfont->ascent + curfont->descent; ty = y + (h / 2) - (th / 2) + curfont->ascent; tx = x + (h / 2); XftDrawStringUtf8(d, &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); } x += tex.w; w -= tex.w; } } if (!*text) { break; } else if (nextfont) { charexists = 0; curfont = nextfont; } else { /* Regardless of whether or not a fallback font is found, the * character must be drawn. */ charexists = 1; if (drw->fontcount >= DRW_FONT_CACHE_SIZE) continue; fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); if (!drw->fonts[0]->pattern) { /* Refer to the comment in drw_font_xcreate for more * information. */ die("the first font in the cache must be loaded from a font string.\n"); } fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); FcCharSetDestroy(fccharset); FcPatternDestroy(fcpattern); if (match) { curfont = drw_font_xcreate(drw, NULL, match); if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) { drw->fonts[drw->fontcount++] = curfont; } else { drw_font_free(curfont); curfont = drw->fonts[0]; } } } } if (d) XftDrawDestroy(d); return x; }
void WebFontInfo::fallbackFontForChar(WebUChar32 c, const char* preferredLocale, WebFallbackFont* fallbackFont) { FcCharSet* cset = FcCharSetCreate(); FcCharSetAddChar(cset, c); FcPattern* pattern = FcPatternCreate(); FcValue fcvalue; fcvalue.type = FcTypeCharSet; fcvalue.u.c = cset; FcPatternAdd(pattern, FC_CHARSET, fcvalue, FcFalse); fcvalue.type = FcTypeBool; fcvalue.u.b = FcTrue; FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse); if (preferredLocale) { FcLangSet* langset = FcLangSetCreate(); FcLangSetAdd(langset, reinterpret_cast<const FcChar8 *>(preferredLocale)); FcPatternAddLangSet(pattern, FC_LANG, langset); FcLangSetDestroy(langset); } FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result); FcPatternDestroy(pattern); FcCharSetDestroy(cset); if (!fontSet) { fallbackFont->name = WebCString(); fallbackFont->isBold = false; fallbackFont->isItalic = false; return; } // Older versions of fontconfig have a bug where they cannot select // only scalable fonts so we have to manually filter the results. for (int i = 0; i < fontSet->nfont; ++i) { FcPattern* current = fontSet->fonts[i]; FcBool isScalable; if (FcPatternGetBool(current, FC_SCALABLE, 0, &isScalable) != FcResultMatch || !isScalable) continue; // fontconfig can also return fonts which are unreadable FcChar8* cFilename; if (FcPatternGetString(current, FC_FILE, 0, &cFilename) != FcResultMatch) continue; if (access(reinterpret_cast<char*>(cFilename), R_OK)) continue; const char* fontFilename = reinterpret_cast<char*>(cFilename); fallbackFont->filename = WebCString(fontFilename, strlen(fontFilename)); // Index into font collection. int ttcIndex; if (FcPatternGetInteger(current, FC_INDEX, 0, &ttcIndex) != FcResultMatch && ttcIndex < 0) continue; fallbackFont->ttcIndex = ttcIndex; FcChar8* familyName; if (FcPatternGetString(current, FC_FAMILY, 0, &familyName) == FcResultMatch) { const char* charFamily = reinterpret_cast<char*>(familyName); fallbackFont->name = WebCString(charFamily, strlen(charFamily)); } int weight; if (FcPatternGetInteger(current, FC_WEIGHT, 0, &weight) == FcResultMatch) fallbackFont->isBold = weight >= FC_WEIGHT_BOLD; else fallbackFont->isBold = false; int slant; if (FcPatternGetInteger(current, FC_SLANT, 0, &slant) == FcResultMatch) fallbackFont->isItalic = slant != FC_SLANT_ROMAN; else fallbackFont->isItalic = false; FcFontSetDestroy(fontSet); return; } FcFontSetDestroy(fontSet); }
static FcCharSet * scan (FILE *f, char *file, FcCharSetFreezer *freezer) { FcCharSet *c = 0; FcCharSet *n; FcBool del; int start, end, ucs4; char buf[1024]; char *line; int lineno = 0; while ((line = get_line (f, buf, &lineno))) { if (!strncmp (line, "include", 7)) { FILE *included_f; char *included_file; included_file = strchr (line, ' '); if (!included_file) fatal (file, lineno, "invalid syntax, expected: include filename"); while (isspace(*included_file)) included_file++; included_f = scanopen (included_file); if (!included_f) fatal (included_file, 0, "can't open"); n = scan (included_f, included_file, freezer); fclose (included_f); if (!c) c = FcCharSetCreate (); if (!FcCharSetMerge (c, n, NULL)) fatal (file, lineno, "out of memory"); FcCharSetDestroy (n); continue; } del = FcFalse; if (line[0] == '-') { del = FcTrue; line++; } if (strchr (line, '-')) { if (sscanf (line, "%x-%x", &start, &end) != 2) fatal (file, lineno, "parse error"); } else { if (sscanf (line, "%x", &start) != 1) fatal (file, lineno, "parse error"); end = start; } if (!c) c = FcCharSetCreate (); for (ucs4 = start; ucs4 <= end; ucs4++) { if (!((del ? FcCharSetDelChar : FcCharSetAddChar) (c, ucs4))) fatal (file, lineno, "out of memory"); } } n = (FcCharSet *) FcCharSetFreeze (freezer, c); FcCharSetDestroy (c); return n; }