File: | xftglyphs.c |
Location: | line 503, column 7 |
Description: | Value stored to 'height' is never read |
1 | /* |
2 | * Copyright © 2000 Keith Packard |
3 | * |
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. |
13 | * |
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. |
21 | */ |
22 | |
23 | #include "xftint.h" |
24 | #include <freetype/ftoutln.h> |
25 | #include <freetype/ftlcdfil.h> |
26 | |
27 | #include <freetype/ftsynth.h> |
28 | |
29 | /* |
30 | * Validate the memory info for a font |
31 | */ |
32 | |
33 | static void |
34 | _XftFontValidateMemory (Display *dpy, XftFont *public) |
35 | { |
36 | XftFontInt *font = (XftFontInt *) public; |
37 | unsigned long glyph_memory; |
38 | FT_UInt glyphindex; |
39 | XftGlyph *xftg; |
40 | |
41 | glyph_memory = 0; |
42 | for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) |
43 | { |
44 | xftg = font->glyphs[glyphindex]; |
45 | if (xftg) |
46 | { |
47 | glyph_memory += xftg->glyph_memory; |
48 | } |
49 | } |
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); |
53 | } |
54 | |
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. |
59 | * |
60 | * this function prepares a target descriptor for this operation. |
61 | * |
62 | * input :: target bitmap descriptor. The function will set its |
63 | * 'width', 'rows' and 'pitch' fields, and only these |
64 | * |
65 | * slot :: the glyph slot containing the source bitmap. this |
66 | * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP |
67 | * |
68 | * mode :: the requested final rendering mode. supported values are |
69 | * MONO, NORMAL (i.e. gray), LCD and LCD_V |
70 | * |
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 |
74 | * |
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) |
77 | */ |
78 | static int |
79 | _compute_xrender_bitmap_size( FT_Bitmap* target, |
80 | FT_GlyphSlot slot, |
81 | FT_Render_Mode mode ) |
82 | { |
83 | FT_Bitmap* ftbit; |
84 | int width, height, pitch; |
85 | |
86 | if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) |
87 | return -1; |
88 | |
89 | // compute the size of the final bitmap |
90 | ftbit = &slot->bitmap; |
91 | |
92 | width = ftbit->width; |
93 | height = ftbit->rows; |
94 | pitch = (width+3) & ~3; |
95 | |
96 | switch ( ftbit->pixel_mode ) |
97 | { |
98 | case FT_PIXEL_MODE_MONO: |
99 | if ( mode == FT_RENDER_MODE_MONO ) |
100 | { |
101 | pitch = (((width+31) & ~31) >> 3); |
102 | break; |
103 | } |
104 | /* fall-through */ |
105 | |
106 | case FT_PIXEL_MODE_GRAY: |
107 | if ( mode == FT_RENDER_MODE_LCD || |
108 | mode == FT_RENDER_MODE_LCD_V ) |
109 | { |
110 | /* each pixel is replicated into a 32-bit ARGB value */ |
111 | pitch = width*4; |
112 | } |
113 | break; |
114 | |
115 | case FT_PIXEL_MODE_LCD: |
116 | if ( mode != FT_RENDER_MODE_LCD ) |
117 | return -1; |
118 | |
119 | /* horz pixel triplets are packed into 32-bit ARGB values */ |
120 | width /= 3; |
121 | pitch = width*4; |
122 | break; |
123 | |
124 | case FT_PIXEL_MODE_LCD_V: |
125 | if ( mode != FT_RENDER_MODE_LCD_V ) |
126 | return -1; |
127 | |
128 | /* vert pixel triplets are packed into 32-bit ARGB values */ |
129 | height /= 3; |
130 | pitch = width*4; |
131 | break; |
132 | |
133 | default: /* unsupported source format */ |
134 | return -1; |
135 | } |
136 | |
137 | target->width = width; |
138 | target->rows = height; |
139 | target->pitch = pitch; |
140 | target->buffer = NULL((void*)0); |
141 | |
142 | return pitch * height; |
143 | } |
144 | |
145 | /* this functions converts the glyph bitmap found in a FT_GlyphSlot |
146 | * into a different format (see _compute_xrender_bitmap_size) |
147 | * |
148 | * you should call this function after _compute_xrender_bitmap_size |
149 | * |
150 | * target :: target bitmap descriptor. Note that its 'buffer' pointer |
151 | * must point to memory allocated by the caller |
152 | * |
153 | * slot :: the glyph slot containing the source bitmap |
154 | * |
155 | * mode :: the requested final rendering mode |
156 | * |
157 | * bgr :: boolean, set if BGR or VBGR pixel ordering is needed |
158 | */ |
159 | static void |
160 | _fill_xrender_bitmap( FT_Bitmap* target, |
161 | FT_GlyphSlot slot, |
162 | FT_Render_Mode mode, |
163 | int bgr ) |
164 | { |
165 | FT_Bitmap* ftbit = &slot->bitmap; |
166 | |
167 | { |
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; |
174 | int subpixel; |
175 | int h; |
176 | |
177 | subpixel = ( mode == FT_RENDER_MODE_LCD || |
178 | mode == FT_RENDER_MODE_LCD_V ); |
179 | |
180 | if ( src_pitch < 0 ) |
181 | srcLine -= src_pitch*(ftbit->rows-1); |
182 | |
183 | switch ( ftbit->pixel_mode ) |
184 | { |
185 | case FT_PIXEL_MODE_MONO: |
186 | if ( subpixel ) /* convert mono to ARGB32 values */ |
187 | { |
188 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
189 | { |
190 | int x; |
191 | |
192 | for ( x = 0; x < width; x++ ) |
193 | { |
194 | if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) |
195 | ((unsigned int*)dstLine)[x] = 0xffffffffU; |
196 | } |
197 | } |
198 | } |
199 | else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */ |
200 | { |
201 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
202 | { |
203 | int x; |
204 | |
205 | for ( x = 0; x < width; x++ ) |
206 | { |
207 | if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) |
208 | dstLine[x] = 0xff; |
209 | } |
210 | } |
211 | } |
212 | else /* copy mono to mono */ |
213 | { |
214 | int bytes = (width+7) >> 3; |
215 | |
216 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
217 | memcpy( dstLine, srcLine, bytes ); |
218 | } |
219 | break; |
220 | |
221 | case FT_PIXEL_MODE_GRAY: |
222 | if ( subpixel ) /* convert gray to ARGB32 values */ |
223 | { |
224 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
225 | { |
226 | int x; |
227 | unsigned int* dst = (unsigned int*)dstLine; |
228 | |
229 | for ( x = 0; x < width; x++ ) |
230 | { |
231 | unsigned int pix = srcLine[x]; |
232 | |
233 | pix |= (pix << 8); |
234 | pix |= (pix << 16); |
235 | |
236 | dst[x] = pix; |
237 | } |
238 | } |
239 | } |
240 | else /* copy gray into gray */ |
241 | { |
242 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
243 | memcpy( dstLine, srcLine, width ); |
244 | } |
245 | break; |
246 | |
247 | case FT_PIXEL_MODE_LCD: |
248 | if ( !bgr ) |
249 | { |
250 | /* convert horizontal RGB into ARGB32 */ |
251 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
252 | { |
253 | int x; |
254 | unsigned char* src = srcLine; |
255 | unsigned int* dst = (unsigned int*)dstLine; |
256 | |
257 | for ( x = 0; x < width; x++, src += 3 ) |
258 | { |
259 | unsigned int pix; |
260 | |
261 | pix = ((unsigned int)src[0] << 16) | |
262 | ((unsigned int)src[1] << 8) | |
263 | ((unsigned int)src[2] ) | |
264 | ((unsigned int)src[1] << 24) ; |
265 | |
266 | dst[x] = pix; |
267 | } |
268 | } |
269 | } |
270 | else |
271 | { |
272 | /* convert horizontal BGR into ARGB32 */ |
273 | for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) |
274 | { |
275 | int x; |
276 | unsigned char* src = srcLine; |
277 | unsigned int* dst = (unsigned int*)dstLine; |
278 | |
279 | for ( x = 0; x < width; x++, src += 3 ) |
280 | { |
281 | unsigned int pix; |
282 | |
283 | pix = ((unsigned int)src[2] << 16) | |
284 | ((unsigned int)src[1] << 8) | |
285 | ((unsigned int)src[0] ) | |
286 | ((unsigned int)src[1] << 24) ; |
287 | |
288 | dst[x] = pix; |
289 | } |
290 | } |
291 | } |
292 | break; |
293 | |
294 | default: /* FT_PIXEL_MODE_LCD_V */ |
295 | /* convert vertical RGB into ARGB32 */ |
296 | if ( !bgr ) |
297 | { |
298 | for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) |
299 | { |
300 | int x; |
301 | unsigned char* src = srcLine; |
302 | unsigned int* dst = (unsigned int*)dstLine; |
303 | |
304 | for ( x = 0; x < width; x++, src += 1 ) |
305 | { |
306 | unsigned int pix; |
307 | |
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) ; |
312 | |
313 | dst[x] = pix; |
314 | } |
315 | } |
316 | } |
317 | else |
318 | { |
319 | for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) |
320 | { |
321 | int x; |
322 | unsigned char* src = srcLine; |
323 | unsigned int* dst = (unsigned int*)dstLine; |
324 | |
325 | for ( x = 0; x < width; x++, src += 1 ) |
326 | { |
327 | unsigned int pix; |
328 | |
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) ; |
333 | |
334 | dst[x] = pix; |
335 | } |
336 | } |
337 | } |
338 | } |
339 | } |
340 | } |
341 | |
342 | _X_EXPORT__attribute__((visibility("default"))) void |
343 | XftFontLoadGlyphs (Display *dpy, |
344 | XftFont *pub, |
345 | FcBool need_bitmaps, |
346 | _Xconstconst FT_UInt *glyphs, |
347 | int nglyph) |
348 | { |
349 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True1); |
350 | XftFontInt *font = (XftFontInt *) pub; |
351 | FT_Error error; |
352 | FT_UInt glyphindex; |
353 | FT_GlyphSlot glyphslot; |
354 | XftGlyph *xftg; |
355 | Glyph glyph; |
356 | unsigned char bufLocal[4096]; |
357 | unsigned char *bufBitmap = bufLocal; |
358 | int bufSize = sizeof (bufLocal); |
359 | int size; |
360 | int width; |
361 | int height; |
362 | int left, right, top, bottom; |
363 | FT_Bitmap* ftbit; |
364 | FT_Bitmap local; |
365 | FT_Vector vector; |
366 | FT_Face face; |
367 | FT_Render_Mode mode = FT_RENDER_MODE_MONO; |
368 | |
369 | if (!info) |
370 | return; |
371 | |
372 | face = XftLockFace (&font->public); |
373 | |
374 | if (!face) |
375 | return; |
376 | |
377 | if (font->info.antialias) |
378 | { |
379 | switch (font->info.rgba) { |
380 | case FC_RGBA_RGB1: |
381 | case FC_RGBA_BGR2: |
382 | mode = FT_RENDER_MODE_LCD; |
383 | break; |
384 | case FC_RGBA_VRGB3: |
385 | case FC_RGBA_VBGR4: |
386 | mode = FT_RENDER_MODE_LCD_V; |
387 | break; |
388 | default: |
389 | mode = FT_RENDER_MODE_NORMAL; |
390 | } |
391 | } |
392 | |
393 | while (nglyph--) |
394 | { |
395 | glyphindex = *glyphs++; |
396 | xftg = font->glyphs[glyphindex]; |
397 | if (!xftg) |
398 | continue; |
399 | |
400 | if (XftDebug() & XFT_DBG_CACHE128) |
401 | _XftFontValidateMemory (dpy, pub); |
402 | /* |
403 | * Check to see if this glyph has just been loaded, |
404 | * this happens when drawing the same glyph twice |
405 | * in a single string |
406 | */ |
407 | if (xftg->glyph_memory) |
408 | continue; |
409 | |
410 | FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter); |
411 | |
412 | error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); |
413 | if (error) |
414 | { |
415 | /* |
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 |
419 | * missing the glyph |
420 | */ |
421 | if (font->info.load_flags & FT_LOAD_NO_BITMAP0x8) |
422 | error = FT_Load_Glyph (face, glyphindex, |
423 | font->info.load_flags & ~FT_LOAD_NO_BITMAP0x8); |
424 | if (error) |
425 | continue; |
426 | } |
427 | |
428 | #define FLOOR(x)((x) & -64) ((x) & -64) |
429 | #define CEIL(x)(((x)+63) & -64) (((x)+63) & -64) |
430 | #define TRUNC(x)((x) >> 6) ((x) >> 6) |
431 | #define ROUND(x)(((x)+32) & -64) (((x)+32) & -64) |
432 | |
433 | glyphslot = face->glyph; |
434 | |
435 | /* |
436 | * Embolden if required |
437 | */ |
438 | if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); |
439 | |
440 | /* |
441 | * Compute glyph metrics from FreeType information |
442 | */ |
443 | if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP) |
444 | { |
445 | /* |
446 | * calculate the true width by transforming all four corners. |
447 | */ |
448 | int xc, yc; |
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_GLYPH32) |
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; |
461 | } else { |
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; |
466 | } |
467 | |
468 | } |
469 | } |
470 | left = FLOOR(left)((left) & -64); |
471 | right = CEIL(right)(((right)+63) & -64); |
472 | bottom = FLOOR(bottom)((bottom) & -64); |
473 | top = CEIL(top)(((top)+63) & -64); |
474 | |
475 | } else { |
476 | left = FLOOR( glyphslot->metrics.horiBearingX )((glyphslot->metrics.horiBearingX) & -64); |
477 | right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width )(((glyphslot->metrics.horiBearingX + glyphslot->metrics .width)+63) & -64); |
478 | |
479 | top = CEIL( glyphslot->metrics.horiBearingY )(((glyphslot->metrics.horiBearingY)+63) & -64); |
480 | bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height )((glyphslot->metrics.horiBearingY - glyphslot->metrics. height) & -64); |
481 | } |
482 | |
483 | width = TRUNC(right - left)((right - left) >> 6); |
484 | height = TRUNC( top - bottom )((top - bottom) >> 6); |
485 | |
486 | /* |
487 | * Clip charcell glyphs to the bounding box |
488 | * XXX transformed? |
489 | */ |
490 | if (font->info.spacing >= FC_CHARCELL110 && !font->info.transform) |
491 | { |
492 | if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT0x10) |
493 | { |
494 | if (TRUNC(bottom)((bottom) >> 6) > font->public.max_advance_width) |
495 | { |
496 | int adjust; |
497 | |
498 | adjust = bottom - (font->public.max_advance_width << 6); |
499 | if (adjust > top) |
500 | adjust = top; |
501 | top -= adjust; |
502 | bottom -= adjust; |
503 | height = font->public.max_advance_width; |
Value stored to 'height' is never read | |
504 | } |
505 | } |
506 | else |
507 | { |
508 | if (TRUNC(right)((right) >> 6) > font->public.max_advance_width) |
509 | { |
510 | int adjust; |
511 | |
512 | adjust = right - (font->public.max_advance_width << 6); |
513 | if (adjust > left) |
514 | adjust = left; |
515 | left -= adjust; |
516 | right -= adjust; |
517 | width = font->public.max_advance_width; |
518 | } |
519 | } |
520 | } |
521 | |
522 | if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP ) |
523 | { |
524 | error = FT_Render_Glyph( face->glyph, mode ); |
525 | if (error) |
526 | continue; |
527 | } |
528 | |
529 | FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE ); |
530 | |
531 | if (font->info.spacing >= FC_MONO100) |
532 | { |
533 | if (font->info.transform) |
534 | { |
535 | if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT0x10) |
536 | { |
537 | vector.x = 0; |
538 | vector.y = -face->size->metrics.max_advance; |
539 | } |
540 | else |
541 | { |
542 | vector.x = face->size->metrics.max_advance; |
543 | vector.y = 0; |
544 | } |
545 | FT_Vector_Transform (&vector, &font->info.matrix); |
546 | xftg->metrics.xOff = vector.x >> 6; |
547 | xftg->metrics.yOff = -(vector.y >> 6); |
548 | } |
549 | else |
550 | { |
551 | if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT0x10) |
552 | { |
553 | xftg->metrics.xOff = 0; |
554 | xftg->metrics.yOff = -font->public.max_advance_width; |
555 | } |
556 | else |
557 | { |
558 | xftg->metrics.xOff = font->public.max_advance_width; |
559 | xftg->metrics.yOff = 0; |
560 | } |
561 | } |
562 | } |
563 | else |
564 | { |
565 | xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x))(((((glyphslot->advance.x)+32) & -64)) >> 6); |
566 | xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y))(((((glyphslot->advance.y)+32) & -64)) >> 6); |
567 | } |
568 | |
569 | // compute the size of the final bitmap |
570 | ftbit = &glyphslot->bitmap; |
571 | |
572 | width = ftbit->width; |
573 | height = ftbit->rows; |
574 | |
575 | if (XftDebug() & XFT_DBG_GLYPH32) |
576 | { |
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, |
584 | width, height); |
585 | if (XftDebug() & XFT_DBG_GLYPHV64) |
586 | { |
587 | int x, y; |
588 | unsigned char *line; |
589 | |
590 | line = ftbit->buffer; |
591 | if (ftbit->pitch < 0) |
592 | line -= ftbit->pitch*(height-1); |
593 | |
594 | for (y = 0; y < height; y++) |
595 | { |
596 | if (font->info.antialias) |
597 | { |
598 | static const char den[] = { " .:;=+*#" }; |
599 | for (x = 0; x < width; x++) |
600 | printf ("%c", den[line[x] >> 5]); |
601 | } |
602 | else |
603 | { |
604 | for (x = 0; x < width * 8; x++) |
605 | { |
606 | printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' '); |
607 | } |
608 | } |
609 | printf ("|\n"); |
610 | line += ftbit->pitch; |
611 | } |
612 | printf ("\n"); |
613 | } |
614 | } |
615 | |
616 | size = _compute_xrender_bitmap_size( &local, glyphslot, mode ); |
617 | if ( size < 0 ) |
618 | continue; |
619 | |
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; |
624 | |
625 | /* |
626 | * If the glyph is relatively large (> 1% of server memory), |
627 | * don't send it until necessary. |
628 | */ |
629 | if (!need_bitmaps && size > info->max_glyph_memory / 100) |
630 | continue; |
631 | |
632 | /* |
633 | * Make sure there is enough buffer space for the glyph. |
634 | */ |
635 | if (size > bufSize) |
636 | { |
637 | if (bufBitmap != bufLocal) |
638 | free (bufBitmap); |
639 | bufBitmap = (unsigned char *) malloc (size); |
640 | if (!bufBitmap) |
641 | continue; |
642 | bufSize = size; |
643 | } |
644 | memset (bufBitmap, 0, size); |
645 | |
646 | local.buffer = bufBitmap; |
647 | |
648 | _fill_xrender_bitmap( &local, glyphslot, mode, |
649 | (font->info.rgba == FC_RGBA_BGR2 || |
650 | font->info.rgba == FC_RGBA_VBGR4 ) ); |
651 | |
652 | /* |
653 | * Copy or convert into local buffer. |
654 | */ |
655 | |
656 | /* |
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 |
661 | * glyphs were freed. |
662 | */ |
663 | glyph = (Glyph) glyphindex; |
664 | |
665 | xftg->glyph_memory = size + sizeof (XftGlyph); |
666 | if (font->format) |
667 | { |
668 | if (!font->glyphset) |
669 | font->glyphset = XRenderCreateGlyphSet (dpy, font->format); |
670 | if ( mode == FT_RENDER_MODE_MONO ) |
671 | { |
672 | /* swap bits in each byte */ |
673 | if (BitmapBitOrder (dpy)(((_XPrivDisplay)dpy)->bitmap_bit_order) != MSBFirst1) |
674 | { |
675 | unsigned char *line = (unsigned char*)bufBitmap; |
676 | int i = size; |
677 | |
678 | while (i--) |
679 | { |
680 | int c = *line; |
681 | c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); |
682 | c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); |
683 | c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); |
684 | *line++ = c; |
685 | } |
686 | } |
687 | } |
688 | else if ( mode != FT_RENDER_MODE_NORMAL ) |
689 | { |
690 | /* invert ARGB <=> BGRA */ |
691 | if (ImageByteOrder (dpy)(((_XPrivDisplay)dpy)->byte_order) != XftNativeByteOrder ()) |
692 | XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2); |
693 | } |
694 | XRenderAddGlyphs (dpy, font->glyphset, &glyph, |
695 | &xftg->metrics, 1, |
696 | (char *) bufBitmap, size); |
697 | } |
698 | else |
699 | { |
700 | if (size) |
701 | { |
702 | xftg->bitmap = malloc (size); |
703 | if (xftg->bitmap) |
704 | memcpy (xftg->bitmap, bufBitmap, size); |
705 | } |
706 | else |
707 | xftg->bitmap = NULL((void*)0); |
708 | } |
709 | |
710 | font->glyph_memory += xftg->glyph_memory; |
711 | info->glyph_memory += xftg->glyph_memory; |
712 | if (XftDebug() & XFT_DBG_CACHE128) |
713 | _XftFontValidateMemory (dpy, pub); |
714 | if (XftDebug() & XFT_DBG_CACHEV256) |
715 | printf ("Caching glyph 0x%x size %ld\n", glyphindex, |
716 | xftg->glyph_memory); |
717 | } |
718 | if (bufBitmap != bufLocal) |
719 | free (bufBitmap); |
720 | XftUnlockFace (&font->public); |
721 | } |
722 | |
723 | _X_EXPORT__attribute__((visibility("default"))) void |
724 | XftFontUnloadGlyphs (Display *dpy, |
725 | XftFont *pub, |
726 | _Xconstconst FT_UInt *glyphs, |
727 | int nglyph) |
728 | { |
729 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); |
730 | XftFontInt *font = (XftFontInt *) pub; |
731 | XftGlyph *xftg; |
732 | FT_UInt glyphindex; |
733 | Glyph glyphBuf[1024]; |
734 | int nused; |
735 | |
736 | nused = 0; |
737 | while (nglyph--) |
738 | { |
739 | glyphindex = *glyphs++; |
740 | xftg = font->glyphs[glyphindex]; |
741 | if (!xftg) |
742 | continue; |
743 | if (xftg->glyph_memory) |
744 | { |
745 | if (font->format) |
746 | { |
747 | if (font->glyphset) |
748 | { |
749 | glyphBuf[nused++] = (Glyph) glyphindex; |
750 | if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) |
751 | { |
752 | XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); |
753 | nused = 0; |
754 | } |
755 | } |
756 | } |
757 | else |
758 | { |
759 | if (xftg->bitmap) |
760 | free (xftg->bitmap); |
761 | } |
762 | font->glyph_memory -= xftg->glyph_memory; |
763 | if (info) |
764 | info->glyph_memory -= xftg->glyph_memory; |
765 | } |
766 | free (xftg); |
767 | XftMemFree (XFT_MEM_GLYPH3, sizeof (XftGlyph)); |
768 | font->glyphs[glyphindex] = NULL((void*)0); |
769 | } |
770 | if (font->glyphset && nused) |
771 | XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); |
772 | } |
773 | |
774 | _X_EXPORT__attribute__((visibility("default"))) FcBool |
775 | XftFontCheckGlyph (Display *dpy, |
776 | XftFont *pub, |
777 | FcBool need_bitmaps, |
778 | FT_UInt glyph, |
779 | FT_UInt *missing, |
780 | int *nmissing) |
781 | { |
782 | XftFontInt *font = (XftFontInt *) pub; |
783 | XftGlyph *xftg; |
784 | int n; |
785 | |
786 | if (glyph >= font->num_glyphs) |
787 | return FcFalse0; |
788 | xftg = font->glyphs[glyph]; |
789 | if (!xftg || (need_bitmaps && !xftg->glyph_memory)) |
790 | { |
791 | if (!xftg) |
792 | { |
793 | xftg = (XftGlyph *) malloc (sizeof (XftGlyph)); |
794 | if (!xftg) |
795 | return FcFalse0; |
796 | XftMemAlloc (XFT_MEM_GLYPH3, sizeof (XftGlyph)); |
797 | xftg->bitmap = NULL((void*)0); |
798 | xftg->glyph_memory = 0; |
799 | font->glyphs[glyph] = xftg; |
800 | } |
801 | n = *nmissing; |
802 | missing[n++] = glyph; |
803 | if (n == XFT_NMISSING256) |
804 | { |
805 | XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); |
806 | n = 0; |
807 | } |
808 | *nmissing = n; |
809 | return FcTrue1; |
810 | } |
811 | else |
812 | return FcFalse0; |
813 | } |
814 | |
815 | _X_EXPORT__attribute__((visibility("default"))) FcBool |
816 | XftCharExists (Display *dpy, |
817 | XftFont *pub, |
818 | FcChar32 ucs4) |
819 | { |
820 | if (pub->charset) |
821 | return FcCharSetHasChar (pub->charset, ucs4); |
822 | return FcFalse0; |
823 | } |
824 | |
825 | #define Missing((FT_UInt) ~0) ((FT_UInt) ~0) |
826 | |
827 | _X_EXPORT__attribute__((visibility("default"))) FT_UInt |
828 | XftCharIndex (Display *dpy, |
829 | XftFont *pub, |
830 | FcChar32 ucs4) |
831 | { |
832 | XftFontInt *font = (XftFontInt *) pub; |
833 | FcChar32 ent, offset; |
834 | FT_Face face; |
835 | |
836 | if (!font->hash_value) |
837 | return 0; |
838 | |
839 | ent = ucs4 % font->hash_value; |
840 | offset = 0; |
841 | while (font->hash_table[ent].ucs4 != ucs4) |
842 | { |
843 | if (font->hash_table[ent].ucs4 == (FcChar32) ~0) |
844 | { |
845 | if (!XftCharExists (dpy, pub, ucs4)) |
846 | return 0; |
847 | face = XftLockFace (pub); |
848 | if (!face) |
849 | return 0; |
850 | font->hash_table[ent].ucs4 = ucs4; |
851 | font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); |
852 | XftUnlockFace (pub); |
853 | break; |
854 | } |
855 | if (!offset) |
856 | { |
857 | offset = ucs4 % font->rehash_value; |
858 | if (!offset) |
859 | offset = 1; |
860 | } |
861 | ent = ent + offset; |
862 | if (ent >= font->hash_value) |
863 | ent -= font->hash_value; |
864 | } |
865 | return font->hash_table[ent].glyph; |
866 | } |
867 | |
868 | /* |
869 | * Pick a random glyph from the font and remove it from the cache |
870 | */ |
871 | _X_HIDDEN__attribute__((visibility("hidden"))) void |
872 | _XftFontUncacheGlyph (Display *dpy, XftFont *pub) |
873 | { |
874 | XftFontInt *font = (XftFontInt *) pub; |
875 | unsigned long glyph_memory; |
876 | FT_UInt glyphindex; |
877 | XftGlyph *xftg; |
878 | |
879 | if (!font->glyph_memory) |
880 | return; |
881 | if (font->use_free_glyphs) |
882 | { |
883 | glyph_memory = rand() % font->glyph_memory; |
884 | } |
885 | else |
886 | { |
887 | if (font->glyphset) |
888 | { |
889 | XRenderFreeGlyphSet (dpy, font->glyphset); |
890 | font->glyphset = 0; |
891 | } |
892 | glyph_memory = 0; |
893 | } |
894 | |
895 | if (XftDebug() & XFT_DBG_CACHE128) |
896 | _XftFontValidateMemory (dpy, pub); |
897 | for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) |
898 | { |
899 | xftg = font->glyphs[glyphindex]; |
900 | if (xftg) |
901 | { |
902 | if (xftg->glyph_memory > glyph_memory) |
903 | { |
904 | if (XftDebug() & XFT_DBG_CACHEV256) |
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) |
909 | continue; |
910 | break; |
911 | } |
912 | glyph_memory -= xftg->glyph_memory; |
913 | } |
914 | } |
915 | if (XftDebug() & XFT_DBG_CACHE128) |
916 | _XftFontValidateMemory (dpy, pub); |
917 | } |
918 | |
919 | _X_HIDDEN__attribute__((visibility("hidden"))) void |
920 | _XftFontManageMemory (Display *dpy, XftFont *pub) |
921 | { |
922 | XftFontInt *font = (XftFontInt *) pub; |
923 | |
924 | if (font->max_glyph_memory) |
925 | { |
926 | if (XftDebug() & XFT_DBG_CACHE128) |
927 | { |
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); |
932 | } |
933 | while (font->glyph_memory > font->max_glyph_memory) |
934 | _XftFontUncacheGlyph (dpy, pub); |
935 | } |
936 | _XftDisplayManageMemory (dpy); |
937 | } |