2 * Copyright © 2000 Keith Packard
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
24 #include <freetype/ftoutln.h>
25 #include <freetype/ftlcdfil.h>
27 #include <freetype/ftsynth.h>
30 * Validate the memory info for a font
34 _XftFontValidateMemory (Display *dpy, XftFont *public)
36 XftFontInt *font = (XftFontInt *) public;
37 unsigned long glyph_memory;
42 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
44 xftg = font->glyphs[glyphindex];
47 glyph_memory += xftg->glyph_memory;
50 if (glyph_memory != font->glyph_memory)
51 printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n",
52 font->glyph_memory, glyph_memory);
55 /* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot
56 * into a different format. For example, we want to convert a
57 * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit
58 * ARGB or ABGR bitmap.
60 * this function prepares a target descriptor for this operation.
62 * input :: target bitmap descriptor. The function will set its
63 * 'width', 'rows' and 'pitch' fields, and only these
65 * slot :: the glyph slot containing the source bitmap. this
66 * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP
68 * mode :: the requested final rendering mode. supported values are
69 * MONO, NORMAL (i.e. gray), LCD and LCD_V
71 * the function returns the size in bytes of the corresponding buffer,
72 * it's up to the caller to allocate the corresponding memory block
73 * before calling _fill_xrender_bitmap
75 * it also returns -1 in case of error (e.g. incompatible arguments,
76 * like trying to convert a gray bitmap into a monochrome one)
79 _compute_xrender_bitmap_size( FT_Bitmap* target,
84 int width, height, pitch;
86 if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
89 // compute the size of the final bitmap
90 ftbit = &slot->bitmap;
94 pitch = (width+3) & ~3;
96 switch ( ftbit->pixel_mode )
98 case FT_PIXEL_MODE_MONO:
99 if ( mode == FT_RENDER_MODE_MONO )
101 pitch = (((width+31) & ~31) >> 3);
106 case FT_PIXEL_MODE_GRAY:
107 if ( mode == FT_RENDER_MODE_LCD ||
108 mode == FT_RENDER_MODE_LCD_V )
110 /* each pixel is replicated into a 32-bit ARGB value */
115 case FT_PIXEL_MODE_LCD:
116 if ( mode != FT_RENDER_MODE_LCD )
119 /* horz pixel triplets are packed into 32-bit ARGB values */
124 case FT_PIXEL_MODE_LCD_V:
125 if ( mode != FT_RENDER_MODE_LCD_V )
128 /* vert pixel triplets are packed into 32-bit ARGB values */
133 default: /* unsupported source format */
137 target->width = width;
138 target->rows = height;
139 target->pitch = pitch;
140 target->buffer = NULL;
142 return pitch * height;
145 /* this functions converts the glyph bitmap found in a FT_GlyphSlot
146 * into a different format (see _compute_xrender_bitmap_size)
148 * you should call this function after _compute_xrender_bitmap_size
150 * target :: target bitmap descriptor. Note that its 'buffer' pointer
151 * must point to memory allocated by the caller
153 * slot :: the glyph slot containing the source bitmap
155 * mode :: the requested final rendering mode
157 * bgr :: boolean, set if BGR or VBGR pixel ordering is needed
160 _fill_xrender_bitmap( FT_Bitmap* target,
165 FT_Bitmap* ftbit = &slot->bitmap;
168 unsigned char* srcLine = ftbit->buffer;
169 unsigned char* dstLine = target->buffer;
170 int src_pitch = ftbit->pitch;
171 int width = target->width;
172 int height = target->rows;
173 int pitch = target->pitch;
177 subpixel = ( mode == FT_RENDER_MODE_LCD ||
178 mode == FT_RENDER_MODE_LCD_V );
181 srcLine -= src_pitch*(ftbit->rows-1);
183 switch ( ftbit->pixel_mode )
185 case FT_PIXEL_MODE_MONO:
186 if ( subpixel ) /* convert mono to ARGB32 values */
188 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
192 for ( x = 0; x < width; x++ )
194 if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) )
195 ((unsigned int*)dstLine)[x] = 0xffffffffU;
199 else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */
201 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
205 for ( x = 0; x < width; x++ )
207 if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) )
212 else /* copy mono to mono */
214 int bytes = (width+7) >> 3;
216 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
217 memcpy( dstLine, srcLine, bytes );
221 case FT_PIXEL_MODE_GRAY:
222 if ( subpixel ) /* convert gray to ARGB32 values */
224 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
227 unsigned int* dst = (unsigned int*)dstLine;
229 for ( x = 0; x < width; x++ )
231 unsigned int pix = srcLine[x];
240 else /* copy gray into gray */
242 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
243 memcpy( dstLine, srcLine, width );
247 case FT_PIXEL_MODE_LCD:
250 /* convert horizontal RGB into ARGB32 */
251 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
254 unsigned char* src = srcLine;
255 unsigned int* dst = (unsigned int*)dstLine;
257 for ( x = 0; x < width; x++, src += 3 )
261 pix = ((unsigned int)src[0] << 16) |
262 ((unsigned int)src[1] << 8) |
263 ((unsigned int)src[2] ) |
264 ((unsigned int)src[1] << 24) ;
272 /* convert horizontal BGR into ARGB32 */
273 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
276 unsigned char* src = srcLine;
277 unsigned int* dst = (unsigned int*)dstLine;
279 for ( x = 0; x < width; x++, src += 3 )
283 pix = ((unsigned int)src[2] << 16) |
284 ((unsigned int)src[1] << 8) |
285 ((unsigned int)src[0] ) |
286 ((unsigned int)src[1] << 24) ;
294 default: /* FT_PIXEL_MODE_LCD_V */
295 /* convert vertical RGB into ARGB32 */
298 for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch )
301 unsigned char* src = srcLine;
302 unsigned int* dst = (unsigned int*)dstLine;
304 for ( x = 0; x < width; x++, src += 1 )
308 pix = ((unsigned int)src[0] << 16) |
309 ((unsigned int)src[src_pitch] << 8) |
310 ((unsigned int)src[src_pitch*2] ) |
311 ((unsigned int)src[src_pitch] << 24) ;
319 for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch )
322 unsigned char* src = srcLine;
323 unsigned int* dst = (unsigned int*)dstLine;
325 for ( x = 0; x < width; x++, src += 1 )
329 pix = ((unsigned int)src[src_pitch*2] << 16) |
330 ((unsigned int)src[src_pitch] << 8) |
331 ((unsigned int)src[0] ) |
332 ((unsigned int)src[src_pitch] << 24) ;
343 XftFontLoadGlyphs (Display *dpy,
346 _Xconst FT_UInt *glyphs,
349 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
350 XftFontInt *font = (XftFontInt *) pub;
353 FT_GlyphSlot glyphslot;
356 unsigned char bufLocal[4096];
357 unsigned char *bufBitmap = bufLocal;
358 int bufSize = sizeof (bufLocal);
362 int left, right, top, bottom;
367 FT_Render_Mode mode = FT_RENDER_MODE_MONO;
372 face = XftLockFace (&font->public);
377 if (font->info.antialias)
379 switch (font->info.rgba) {
382 mode = FT_RENDER_MODE_LCD;
386 mode = FT_RENDER_MODE_LCD_V;
389 mode = FT_RENDER_MODE_NORMAL;
395 glyphindex = *glyphs++;
396 xftg = font->glyphs[glyphindex];
400 if (XftDebug() & XFT_DBG_CACHE)
401 _XftFontValidateMemory (dpy, pub);
403 * Check to see if this glyph has just been loaded,
404 * this happens when drawing the same glyph twice
407 if (xftg->glyph_memory)
410 FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter);
412 error = FT_Load_Glyph (face, glyphindex, font->info.load_flags);
416 * If anti-aliasing or transforming glyphs and
417 * no outline version exists, fallback to the
418 * bitmap and let things look bad instead of
421 if (font->info.load_flags & FT_LOAD_NO_BITMAP)
422 error = FT_Load_Glyph (face, glyphindex,
423 font->info.load_flags & ~FT_LOAD_NO_BITMAP);
428 #define FLOOR(x) ((x) & -64)
429 #define CEIL(x) (((x)+63) & -64)
430 #define TRUNC(x) ((x) >> 6)
431 #define ROUND(x) (((x)+32) & -64)
433 glyphslot = face->glyph;
436 * Embolden if required
438 if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot);
441 * Compute glyph metrics from FreeType information
443 if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP)
446 * calculate the true width by transforming all four corners.
449 left = right = top = bottom = 0;
450 for(xc = 0; xc <= 1; xc ++) {
451 for(yc = 0; yc <= 1; yc++) {
452 vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width;
453 vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height;
454 FT_Vector_Transform(&vector, &font->info.matrix);
455 if (XftDebug() & XFT_DBG_GLYPH)
456 printf("Trans %d %d: %d %d\n", (int) xc, (int) yc,
457 (int) vector.x, (int) vector.y);
458 if(xc == 0 && yc == 0) {
459 left = right = vector.x;
460 top = bottom = vector.y;
462 if(left > vector.x) left = vector.x;
463 if(right < vector.x) right = vector.x;
464 if(bottom > vector.y) bottom = vector.y;
465 if(top < vector.y) top = vector.y;
472 bottom = FLOOR(bottom);
476 left = FLOOR( glyphslot->metrics.horiBearingX );
477 right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width );
479 top = CEIL( glyphslot->metrics.horiBearingY );
480 bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height );
483 width = TRUNC(right - left);
484 height = TRUNC( top - bottom );
487 * Clip charcell glyphs to the bounding box
490 if (font->info.spacing >= FC_CHARCELL && !font->info.transform)
492 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
494 if (TRUNC(bottom) > font->public.max_advance_width)
498 adjust = bottom - (font->public.max_advance_width << 6);
503 height = font->public.max_advance_width;
508 if (TRUNC(right) > font->public.max_advance_width)
512 adjust = right - (font->public.max_advance_width << 6);
517 width = font->public.max_advance_width;
522 if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP )
524 error = FT_Render_Glyph( face->glyph, mode );
529 FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE );
531 if (font->info.spacing >= FC_MONO)
533 if (font->info.transform)
535 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
538 vector.y = -face->size->metrics.max_advance;
542 vector.x = face->size->metrics.max_advance;
545 FT_Vector_Transform (&vector, &font->info.matrix);
546 xftg->metrics.xOff = vector.x >> 6;
547 xftg->metrics.yOff = -(vector.y >> 6);
551 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
553 xftg->metrics.xOff = 0;
554 xftg->metrics.yOff = -font->public.max_advance_width;
558 xftg->metrics.xOff = font->public.max_advance_width;
559 xftg->metrics.yOff = 0;
565 xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x));
566 xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y));
569 // compute the size of the final bitmap
570 ftbit = &glyphslot->bitmap;
572 width = ftbit->width;
573 height = ftbit->rows;
575 if (XftDebug() & XFT_DBG_GLYPH)
577 printf ("glyph %d:\n", (int) glyphindex);
578 printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n",
579 (int) glyphslot->metrics.horiBearingX,
580 (int) glyphslot->metrics.horiBearingY,
581 (int) glyphslot->metrics.width,
582 (int) glyphslot->metrics.height,
583 left, right, top, bottom,
585 if (XftDebug() & XFT_DBG_GLYPHV)
590 line = ftbit->buffer;
591 if (ftbit->pitch < 0)
592 line -= ftbit->pitch*(height-1);
594 for (y = 0; y < height; y++)
596 if (font->info.antialias)
598 static const char den[] = { " .:;=+*#" };
599 for (x = 0; x < width; x++)
600 printf ("%c", den[line[x] >> 5]);
604 for (x = 0; x < width * 8; x++)
606 printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' ');
610 line += ftbit->pitch;
616 size = _compute_xrender_bitmap_size( &local, glyphslot, mode );
620 xftg->metrics.width = local.width;
621 xftg->metrics.height = local.rows;
622 xftg->metrics.x = - glyphslot->bitmap_left;
623 xftg->metrics.y = glyphslot->bitmap_top;
626 * If the glyph is relatively large (> 1% of server memory),
627 * don't send it until necessary.
629 if (!need_bitmaps && size > info->max_glyph_memory / 100)
633 * Make sure there is enough buffer space for the glyph.
637 if (bufBitmap != bufLocal)
639 bufBitmap = (unsigned char *) malloc (size);
644 memset (bufBitmap, 0, size);
646 local.buffer = bufBitmap;
648 _fill_xrender_bitmap( &local, glyphslot, mode,
649 (font->info.rgba == FC_RGBA_BGR ||
650 font->info.rgba == FC_RGBA_VBGR ) );
653 * Copy or convert into local buffer.
657 * Use the glyph index as the wire encoding; it
658 * might be more efficient for some locales to map
659 * these by first usage to smaller values, but that
660 * would require persistently storing the map when
663 glyph = (Glyph) glyphindex;
665 xftg->glyph_memory = size + sizeof (XftGlyph);
669 font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
670 if ( mode == FT_RENDER_MODE_MONO )
672 /* swap bits in each byte */
673 if (BitmapBitOrder (dpy) != MSBFirst)
675 unsigned char *line = (unsigned char*)bufBitmap;
681 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
682 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
683 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
688 else if ( mode != FT_RENDER_MODE_NORMAL )
690 /* invert ARGB <=> BGRA */
691 if (ImageByteOrder (dpy) != XftNativeByteOrder ())
692 XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2);
694 XRenderAddGlyphs (dpy, font->glyphset, &glyph,
696 (char *) bufBitmap, size);
702 xftg->bitmap = malloc (size);
704 memcpy (xftg->bitmap, bufBitmap, size);
710 font->glyph_memory += xftg->glyph_memory;
711 info->glyph_memory += xftg->glyph_memory;
712 if (XftDebug() & XFT_DBG_CACHE)
713 _XftFontValidateMemory (dpy, pub);
714 if (XftDebug() & XFT_DBG_CACHEV)
715 printf ("Caching glyph 0x%x size %ld\n", glyphindex,
718 if (bufBitmap != bufLocal)
720 XftUnlockFace (&font->public);
724 XftFontUnloadGlyphs (Display *dpy,
726 _Xconst FT_UInt *glyphs,
729 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
730 XftFontInt *font = (XftFontInt *) pub;
733 Glyph glyphBuf[1024];
739 glyphindex = *glyphs++;
740 xftg = font->glyphs[glyphindex];
743 if (xftg->glyph_memory)
749 glyphBuf[nused++] = (Glyph) glyphindex;
750 if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0]))
752 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
762 font->glyph_memory -= xftg->glyph_memory;
764 info->glyph_memory -= xftg->glyph_memory;
767 XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph));
768 font->glyphs[glyphindex] = NULL;
770 if (font->glyphset && nused)
771 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
775 XftFontCheckGlyph (Display *dpy,
782 XftFontInt *font = (XftFontInt *) pub;
786 if (glyph >= font->num_glyphs)
788 xftg = font->glyphs[glyph];
789 if (!xftg || (need_bitmaps && !xftg->glyph_memory))
793 xftg = (XftGlyph *) malloc (sizeof (XftGlyph));
796 XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph));
798 xftg->glyph_memory = 0;
799 font->glyphs[glyph] = xftg;
802 missing[n++] = glyph;
803 if (n == XFT_NMISSING)
805 XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n);
816 XftCharExists (Display *dpy,
821 return FcCharSetHasChar (pub->charset, ucs4);
825 #define Missing ((FT_UInt) ~0)
828 XftCharIndex (Display *dpy,
832 XftFontInt *font = (XftFontInt *) pub;
833 FcChar32 ent, offset;
836 if (!font->hash_value)
839 ent = ucs4 % font->hash_value;
841 while (font->hash_table[ent].ucs4 != ucs4)
843 if (font->hash_table[ent].ucs4 == (FcChar32) ~0)
845 if (!XftCharExists (dpy, pub, ucs4))
847 face = XftLockFace (pub);
850 font->hash_table[ent].ucs4 = ucs4;
851 font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4);
857 offset = ucs4 % font->rehash_value;
862 if (ent >= font->hash_value)
863 ent -= font->hash_value;
865 return font->hash_table[ent].glyph;
869 * Pick a random glyph from the font and remove it from the cache
872 _XftFontUncacheGlyph (Display *dpy, XftFont *pub)
874 XftFontInt *font = (XftFontInt *) pub;
875 unsigned long glyph_memory;
879 if (!font->glyph_memory)
881 if (font->use_free_glyphs)
883 glyph_memory = rand() % font->glyph_memory;
889 XRenderFreeGlyphSet (dpy, font->glyphset);
895 if (XftDebug() & XFT_DBG_CACHE)
896 _XftFontValidateMemory (dpy, pub);
897 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
899 xftg = font->glyphs[glyphindex];
902 if (xftg->glyph_memory > glyph_memory)
904 if (XftDebug() & XFT_DBG_CACHEV)
905 printf ("Uncaching glyph 0x%x size %ld\n",
906 glyphindex, xftg->glyph_memory);
907 XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
908 if (!font->use_free_glyphs)
912 glyph_memory -= xftg->glyph_memory;
915 if (XftDebug() & XFT_DBG_CACHE)
916 _XftFontValidateMemory (dpy, pub);
920 _XftFontManageMemory (Display *dpy, XftFont *pub)
922 XftFontInt *font = (XftFontInt *) pub;
924 if (font->max_glyph_memory)
926 if (XftDebug() & XFT_DBG_CACHE)
928 if (font->glyph_memory > font->max_glyph_memory)
929 printf ("Reduce memory for font 0x%lx from %ld to %ld\n",
930 font->glyphset ? font->glyphset : (unsigned long) font,
931 font->glyph_memory, font->max_glyph_memory);
933 while (font->glyph_memory > font->max_glyph_memory)
934 _XftFontUncacheGlyph (dpy, pub);
936 _XftDisplayManageMemory (dpy);