Lines 23-30
Link Here
|
23 |
*/ |
23 |
*/ |
24 |
|
24 |
|
25 |
#include "xftint.h" |
25 |
#include "xftint.h" |
26 |
#include <freetype/ftoutln.h> |
26 |
#include FT_OUTLINE_H |
|
|
27 |
#if HAVE_FT_GLYPHSLOT_EMBOLDEN |
28 |
#include FT_SYNTHESIS_H |
29 |
#endif |
30 |
|
31 |
|
32 |
/* define the following macro if you want to use a small FIR filter to |
33 |
* reduce color fringes for LCD rendering. If undefined, the original |
34 |
* weird pixel-local color balancing algorithm will be used |
35 |
*/ |
36 |
#define FIR_FILTER |
27 |
|
37 |
|
|
|
38 |
#ifdef FIR_FILTER |
39 |
/* note: keep the filter symetric, or bad things will happen */ |
40 |
static const int fir_filter[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 }; |
41 |
|
42 |
#else /* !FIR_FILTER */ |
28 |
static const int filters[3][3] = { |
43 |
static const int filters[3][3] = { |
29 |
/* red */ |
44 |
/* red */ |
30 |
#if 0 |
45 |
#if 0 |
Lines 40-45
static const int filters[3][3] = {
Link Here
|
40 |
/* blue */ |
55 |
/* blue */ |
41 |
{ 65538*1/13,65538*3/13,65538*9/13 }, |
56 |
{ 65538*1/13,65538*3/13,65538*9/13 }, |
42 |
}; |
57 |
}; |
|
|
58 |
#endif /* !FIR_FILTER */ |
43 |
|
59 |
|
44 |
/* |
60 |
/* |
45 |
* Validate the memory info for a font |
61 |
* Validate the memory info for a font |
Lines 131-136
XftFontLoadGlyphs (Display *dpy,
Link Here
|
131 |
|
147 |
|
132 |
while (nglyph--) |
148 |
while (nglyph--) |
133 |
{ |
149 |
{ |
|
|
150 |
#ifdef FIR_FILTER |
151 |
int margin_top = 0, margin_left = 0; |
152 |
#endif |
153 |
|
134 |
glyphindex = *glyphs++; |
154 |
glyphindex = *glyphs++; |
135 |
xftg = font->glyphs[glyphindex]; |
155 |
xftg = font->glyphs[glyphindex]; |
136 |
if (!xftg) |
156 |
if (!xftg) |
Lines 169-174
XftFontLoadGlyphs (Display *dpy,
Link Here
|
169 |
|
189 |
|
170 |
glyphslot = face->glyph; |
190 |
glyphslot = face->glyph; |
171 |
|
191 |
|
|
|
192 |
if (font->info.embolden && |
193 |
glyphslot->format == ft_glyph_format_outline && |
194 |
glyphslot->outline.n_points && |
195 |
pub->height <= 18 && |
196 |
!font->info.antialias && |
197 |
!(font->info.load_flags & FT_LOAD_NO_HINTING)) { |
198 |
error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_MONO); |
199 |
if (error) |
200 |
continue; |
201 |
} |
202 |
|
172 |
#if HAVE_FT_GLYPHSLOT_EMBOLDEN |
203 |
#if HAVE_FT_GLYPHSLOT_EMBOLDEN |
173 |
/* |
204 |
/* |
174 |
* Embolden if required |
205 |
* Embolden if required |
Lines 179-185
XftFontLoadGlyphs (Display *dpy,
Link Here
|
179 |
/* |
210 |
/* |
180 |
* Compute glyph metrics from FreeType information |
211 |
* Compute glyph metrics from FreeType information |
181 |
*/ |
212 |
*/ |
182 |
if(font->info.transform && glyphslot->format != ft_glyph_format_bitmap) |
213 |
if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP) |
183 |
{ |
214 |
{ |
184 |
/* |
215 |
/* |
185 |
* calculate the true width by transforming all four corners. |
216 |
* calculate the true width by transforming all four corners. |
Lines 258-269
XftFontLoadGlyphs (Display *dpy,
Link Here
|
258 |
} |
289 |
} |
259 |
} |
290 |
} |
260 |
|
291 |
|
261 |
if (font->info.antialias) |
292 |
/* now we're going to adjust the margins of the glyph for LCD filtering */ |
262 |
pitch = (width * hmul + 3) & ~3; |
293 |
if (font->info.antialias) { |
263 |
else |
294 |
switch (font->info.rgba) { |
264 |
pitch = ((width + 31) & ~31) >> 3; |
295 |
case FC_RGBA_RGB: |
265 |
|
296 |
case FC_RGBA_BGR: |
266 |
size = pitch * height * vmul; |
297 |
#ifdef FIR_FILTER |
|
|
298 |
margin_left = 1; |
299 |
left -= 64; |
300 |
right += 64; |
301 |
width += 2; |
302 |
#endif /* FIR_FILTER */ |
303 |
pitch = (width*3+3) & ~3; |
304 |
size = pitch*height; |
305 |
break; |
306 |
|
307 |
case FC_RGBA_VRGB: |
308 |
case FC_RGBA_VBGR: |
309 |
#ifdef FIR_FILTER |
310 |
margin_top = 0; |
311 |
top += 64; |
312 |
bottom -= 64; |
313 |
height += 2; |
314 |
#endif /* FIR_FILTER */ |
315 |
pitch = (width+3) & ~3; |
316 |
size = pitch*height*3; |
317 |
break; |
318 |
|
319 |
default: |
320 |
pitch = (width+3) & ~3; |
321 |
size = pitch*height; |
322 |
} |
323 |
} else { |
324 |
pitch = ((width+31) & ~31) >> 3; |
325 |
size = pitch*height; |
326 |
} |
267 |
|
327 |
|
268 |
xftg->metrics.width = width; |
328 |
xftg->metrics.width = width; |
269 |
xftg->metrics.height = height; |
329 |
xftg->metrics.height = height; |
Lines 323-330
XftFontLoadGlyphs (Display *dpy,
Link Here
|
323 |
if (bufBitmap != bufLocal) |
383 |
if (bufBitmap != bufLocal) |
324 |
free (bufBitmap); |
384 |
free (bufBitmap); |
325 |
bufBitmap = (unsigned char *) malloc (size); |
385 |
bufBitmap = (unsigned char *) malloc (size); |
326 |
if (!bufBitmap) |
386 |
if (!bufBitmap) { |
|
|
387 |
bufBitmap = bufLocal; /* prevent free(NULL) later !! */ |
327 |
continue; |
388 |
continue; |
|
|
389 |
} |
328 |
bufSize = size; |
390 |
bufSize = size; |
329 |
} |
391 |
} |
330 |
memset (bufBitmap, 0, size); |
392 |
memset (bufBitmap, 0, size); |
Lines 333-339
XftFontLoadGlyphs (Display *dpy,
Link Here
|
333 |
* Rasterize into the local buffer |
395 |
* Rasterize into the local buffer |
334 |
*/ |
396 |
*/ |
335 |
switch (glyphslot->format) { |
397 |
switch (glyphslot->format) { |
336 |
case ft_glyph_format_outline: |
398 |
case FT_GLYPH_FORMAT_OUTLINE: |
337 |
ftbit.width = width * hmul; |
399 |
ftbit.width = width * hmul; |
338 |
ftbit.rows = height * vmul; |
400 |
ftbit.rows = height * vmul; |
339 |
ftbit.pitch = pitch; |
401 |
ftbit.pitch = pitch; |
Lines 351-385
XftFontLoadGlyphs (Display *dpy,
Link Here
|
351 |
|
413 |
|
352 |
FT_Outline_Get_Bitmap( _XftFTlibrary, &glyphslot->outline, &ftbit ); |
414 |
FT_Outline_Get_Bitmap( _XftFTlibrary, &glyphslot->outline, &ftbit ); |
353 |
break; |
415 |
break; |
354 |
case ft_glyph_format_bitmap: |
416 |
case FT_GLYPH_FORMAT_BITMAP: |
355 |
if (font->info.antialias) |
417 |
if (font->info.antialias) |
356 |
{ |
418 |
{ |
357 |
unsigned char *srcLine, *dstLine; |
419 |
unsigned char *srcLine, *dstLine; |
358 |
int height; |
420 |
int height; |
|
|
421 |
int width = glyphslot->bitmap.width; |
359 |
int x; |
422 |
int x; |
360 |
int h, v; |
|
|
361 |
|
423 |
|
362 |
srcLine = glyphslot->bitmap.buffer; |
424 |
srcLine = glyphslot->bitmap.buffer; |
363 |
dstLine = bufBitmap; |
425 |
dstLine = bufBitmap + margin_left + margin_top*pitch; |
364 |
height = glyphslot->bitmap.rows; |
426 |
height = glyphslot->bitmap.rows; |
365 |
while (height--) |
427 |
while (height--) |
366 |
{ |
428 |
{ |
367 |
for (x = 0; x < glyphslot->bitmap.width; x++) |
429 |
unsigned char* src = srcLine; |
|
|
430 |
unsigned char* dst = dstLine; |
431 |
unsigned int mask = 0x8080; |
432 |
|
433 |
for (x = 0; x < width; x++ ) |
368 |
{ |
434 |
{ |
369 |
/* always MSB bitmaps */ |
435 |
if ( (src[0] & mask) != 0 ) { |
370 |
unsigned char a = ((srcLine[x >> 3] & (0x80 >> (x & 7))) ? |
436 |
dst[0] = 0xFF; |
371 |
0xff : 0x00); |
437 |
if ( hmul == 3 ) { |
372 |
if (subpixel) |
438 |
dst[1] = 0xFF; |
373 |
{ |
439 |
dst[2] = 0xFF; |
374 |
for (v = 0; v < vmul; v++) |
440 |
} |
375 |
for (h = 0; h < hmul; h++) |
441 |
} |
376 |
dstLine[v * pitch + x*hmul + h] = a; |
442 |
|
377 |
} |
443 |
mask >>= 1; |
378 |
else |
444 |
if ( (mask & 0x80) != 0 ) { |
379 |
dstLine[x] = a; |
445 |
mask = 0x8080; |
380 |
} |
446 |
src += 1; |
381 |
dstLine += pitch * vmul; |
447 |
} |
382 |
srcLine += glyphslot->bitmap.pitch; |
448 |
} |
|
|
449 |
|
450 |
if ( vmul == 3 ) { |
451 |
memcpy( dstLine + pitch, dstLine, width*3 ); |
452 |
dstLine += pitch; |
453 |
|
454 |
memcpy( dstLine + pitch, dstLine, width*3 ); |
455 |
dstLine += pitch; |
456 |
} |
457 |
|
458 |
dstLine += pitch; |
459 |
srcLine += width; |
383 |
} |
460 |
} |
384 |
} |
461 |
} |
385 |
else |
462 |
else |
Lines 455-528
XftFontLoadGlyphs (Display *dpy,
Link Here
|
455 |
|
532 |
|
456 |
if (subpixel) |
533 |
if (subpixel) |
457 |
{ |
534 |
{ |
458 |
int x, y; |
535 |
widthrgba = width; |
459 |
unsigned char *in_line, *out_line, *in; |
536 |
pitchrgba = (widthrgba * 4 + 3) & ~3; |
460 |
unsigned int *out; |
537 |
sizergba = pitchrgba * height; |
461 |
unsigned int red, green, blue; |
538 |
|
462 |
int rf, gf, bf; |
539 |
if (sizergba > bufSizeRgba) |
463 |
int s; |
540 |
{ |
464 |
int o, os; |
541 |
if (bufBitmapRgba != bufLocalRgba) |
465 |
|
542 |
free (bufBitmapRgba); |
466 |
/* |
543 |
bufBitmapRgba = (unsigned char *) malloc (sizergba); |
467 |
* Filter the glyph to soften the color fringes |
544 |
if (!bufBitmapRgba) { |
468 |
*/ |
545 |
bufBitmapRgba = bufLocalRgba; /* prevent free(NULL) later !! */ |
469 |
widthrgba = width; |
546 |
continue; |
470 |
pitchrgba = (widthrgba * 4 + 3) & ~3; |
547 |
} |
471 |
sizergba = pitchrgba * height; |
548 |
bufSizeRgba = sizergba; |
472 |
|
549 |
} |
473 |
os = 1; |
550 |
memset (bufBitmapRgba, 0, sizergba); |
474 |
switch (font->info.rgba) { |
551 |
|
475 |
case FC_RGBA_VRGB: |
552 |
#ifdef FIR_FILTER |
476 |
os = pitch; |
553 |
{ |
477 |
case FC_RGBA_RGB: |
554 |
unsigned char* line; |
478 |
default: |
555 |
|
479 |
rf = 0; |
556 |
/* perform in-place FIR filtering in either the horizontal or |
480 |
gf = 1; |
557 |
* vertical direction |
481 |
bf = 2; |
558 |
*/ |
482 |
break; |
559 |
switch (font->info.rgba) { |
483 |
case FC_RGBA_VBGR: |
560 |
case FC_RGBA_RGB: |
484 |
os = pitch; |
561 |
case FC_RGBA_BGR: |
485 |
case FC_RGBA_BGR: |
562 |
{ |
486 |
bf = 0; |
563 |
int h; |
487 |
gf = 1; |
564 |
|
488 |
rf = 2; |
565 |
line = bufBitmap; |
489 |
break; |
566 |
for ( h = height; h > 0; h--, line += pitch ) { |
490 |
} |
567 |
int pix[6] = { 0, 0, 0, 0, 0, 0 }; |
491 |
if (sizergba > bufSizeRgba) |
568 |
unsigned char* p = line; |
492 |
{ |
569 |
unsigned char* limit = line + width*3; |
493 |
if (bufBitmapRgba != bufLocalRgba) |
570 |
int nn, val, val2; |
494 |
free (bufBitmapRgba); |
571 |
|
495 |
bufBitmapRgba = (unsigned char *) malloc (sizergba); |
572 |
val = p[0]; |
496 |
if (!bufBitmapRgba) |
573 |
for (nn = 0; nn < 3; nn++) |
497 |
continue; |
574 |
pix[2+nn] += val*fir_filter[nn]; |
498 |
bufSizeRgba = sizergba; |
575 |
|
499 |
} |
576 |
val = p[1]; |
500 |
memset (bufBitmapRgba, 0, sizergba); |
577 |
for (nn = 0; nn < 4; nn++) |
501 |
in_line = bufBitmap; |
578 |
pix[1+nn] += val*fir_filter[nn]; |
502 |
out_line = bufBitmapRgba; |
579 |
|
503 |
for (y = 0; y < height; y++) |
580 |
p += 2; |
504 |
{ |
581 |
|
505 |
in = in_line; |
582 |
for ( ; p < limit; p++ ) { |
506 |
out = (unsigned int *) out_line; |
583 |
val = p[0]; |
507 |
in_line += pitch * vmul; |
584 |
for (nn = 0; nn < 5; nn++) |
508 |
out_line += pitchrgba; |
585 |
pix[nn] += val*fir_filter[nn]; |
509 |
for (x = 0; x < width * hmul; x += hmul) |
586 |
|
510 |
{ |
587 |
val2 = pix[0]/255; |
511 |
red = green = blue = 0; |
588 |
if (val2 > 255) val2 = 255; |
512 |
o = 0; |
589 |
p[-2] = (unsigned char)val2; |
513 |
for (s = 0; s < 3; s++) |
590 |
|
514 |
{ |
591 |
for (nn = 0; nn < 5; nn++) |
515 |
red += filters[rf][s]*in[x+o]; |
592 |
pix[nn] = pix[nn+1]; |
516 |
green += filters[gf][s]*in[x+o]; |
593 |
} |
517 |
blue += filters[bf][s]*in[x+o]; |
594 |
for (nn = 0; nn < 2; nn++ ) { |
518 |
o += os; |
595 |
val2 = pix[nn]/255; |
519 |
} |
596 |
if (val2 > 255) val2 = 255; |
520 |
red = red / 65536; |
597 |
p[nn-2] = (unsigned char)val2; |
521 |
green = green / 65536; |
598 |
} |
522 |
blue = blue / 65536; |
599 |
} |
523 |
*out++ = (green << 24) | (red << 16) | (green << 8) | blue; |
600 |
} |
524 |
} |
601 |
break; |
525 |
} |
602 |
|
|
|
603 |
case FC_RGBA_VRGB: |
604 |
case FC_RGBA_VBGR: |
605 |
{ |
606 |
int w; |
607 |
|
608 |
for (w = 0; w < width; w++ ) { |
609 |
int pix[6] = { 0, 0, 0, 0, 0, 0 }; |
610 |
unsigned char* p = bufBitmap + w; |
611 |
unsigned char* limit = bufBitmap + w + height*3*pitch; |
612 |
int nn, val, val2; |
613 |
|
614 |
val = p[0]; |
615 |
for (nn = 0; nn < 3; nn++) |
616 |
pix[2+nn] += val*fir_filter[nn]; |
617 |
|
618 |
val = p[pitch]; |
619 |
for (nn = 0; nn < 4; nn++ ) |
620 |
pix[1+nn] += val*fir_filter[nn]; |
621 |
|
622 |
p += 2*pitch; |
623 |
for ( ; p < limit; p += pitch ) { |
624 |
val = p[0]; |
625 |
for (nn = 0; nn < 5; nn++ ) |
626 |
pix[nn] += val*fir_filter[nn]; |
627 |
|
628 |
val2 = pix[0]/255; |
629 |
if (val2 > 255) val2 = 255; |
630 |
p[-2*pitch] = (unsigned char)val2; |
631 |
|
632 |
for (nn = 0; nn < 5; nn++) |
633 |
pix[nn] = pix[nn+1]; |
634 |
} |
635 |
|
636 |
for (nn = 0; nn < 2; nn++) { |
637 |
val2 = pix[nn]/255; |
638 |
if (val2 > 255) val2 = 255; |
639 |
p[(nn-2)*pitch] = (unsigned char)val2; |
640 |
} |
641 |
} |
642 |
} |
643 |
break; |
644 |
|
645 |
default: |
646 |
; |
647 |
} |
648 |
|
649 |
/* now copy the resulting RGB graymap into an ARGB map */ |
650 |
{ |
651 |
unsigned char* in_line = bufBitmap; |
652 |
unsigned char* out_line = bufBitmapRgba; |
653 |
int h; |
654 |
|
655 |
switch (font->info.rgba) { |
656 |
case FC_RGBA_RGB: |
657 |
for (h = height; h > 0; h--) { |
658 |
unsigned char* in = in_line; |
659 |
int* out = (int*)out_line; |
660 |
int w; |
661 |
|
662 |
for (w = width; w > 0; w--, in += 3, out += 1) { |
663 |
int r = in[0]; |
664 |
int g = in[1]; |
665 |
int b = in[2]; |
666 |
|
667 |
out[0] = (g << 24) | (r << 16) | (g << 8) | (b); |
668 |
} |
669 |
|
670 |
in_line += pitch; |
671 |
out_line += pitchrgba; |
672 |
} |
673 |
break; |
674 |
|
675 |
case FC_RGBA_BGR: |
676 |
for (h = height; h > 0; h--) { |
677 |
unsigned char* in = in_line; |
678 |
int* out = (int*)out_line; |
679 |
int w; |
680 |
|
681 |
for (w = width; w > 0; w--, in += 3, out += 1) { |
682 |
int r = in[0]; |
683 |
int g = in[1]; |
684 |
int b = in[2]; |
685 |
|
686 |
out[0] = (g << 24) | (b << 16) | (g << 8) | (r); |
687 |
} |
688 |
|
689 |
in_line += pitch; |
690 |
out_line += pitchrgba; |
691 |
} |
692 |
break; |
693 |
|
694 |
case FC_RGBA_VRGB: |
695 |
for (h = height; h > 0; h--) { |
696 |
unsigned char* in = in_line; |
697 |
unsigned char* out = out_line; |
698 |
int w; |
699 |
|
700 |
for (w = width; w > 0; w--, in += 1, out += 4) { |
701 |
int r = in[0*pitch]; |
702 |
int g = in[1*pitch]; |
703 |
int b = in[2*pitch]; |
704 |
|
705 |
((int*)out)[0] = (g << 24) | (r << 16) | (g << 8) | (b); |
706 |
} |
707 |
|
708 |
in_line += 3*pitch; |
709 |
out_line += pitchrgba; |
710 |
} |
711 |
break; |
712 |
|
713 |
case FC_RGBA_VBGR: |
714 |
for (h = height; h > 0; h--) { |
715 |
unsigned char* in = in_line; |
716 |
unsigned char* out = out_line; |
717 |
int w; |
718 |
|
719 |
for (w = width; w > 0; w--, in += 1, out += 4) { |
720 |
int r = in[0*pitch]; |
721 |
int g = in[1*pitch]; |
722 |
int b = in[2*pitch]; |
723 |
|
724 |
((int*)out)[0] = (g << 24) | (b << 16) | (g << 8) | (r); |
725 |
} |
726 |
|
727 |
in_line += 3*pitch; |
728 |
out_line += pitchrgba; |
729 |
} |
730 |
break; |
731 |
|
732 |
default: |
733 |
; |
734 |
} |
735 |
} |
736 |
} |
737 |
#else /* !FIR_FILTER */ |
738 |
{ |
739 |
int x, y; |
740 |
unsigned char *in_line, *out_line, *in; |
741 |
unsigned int *out; |
742 |
unsigned int red, green, blue; |
743 |
int rf, gf, bf; |
744 |
int s; |
745 |
int o, os; |
746 |
|
747 |
/* |
748 |
* Filter the glyph to soften the color fringes |
749 |
*/ |
750 |
widthrgba = width; |
751 |
pitchrgba = (widthrgba * 4 + 3) & ~3; |
752 |
sizergba = pitchrgba * height; |
753 |
|
754 |
os = 1; |
755 |
switch (font->info.rgba) { |
756 |
case FC_RGBA_VRGB: |
757 |
os = pitch; |
758 |
case FC_RGBA_RGB: |
759 |
default: |
760 |
rf = 0; |
761 |
gf = 1; |
762 |
bf = 2; |
763 |
break; |
764 |
case FC_RGBA_VBGR: |
765 |
os = pitch; |
766 |
case FC_RGBA_BGR: |
767 |
bf = 0; |
768 |
gf = 1; |
769 |
rf = 2; |
770 |
break; |
771 |
} |
772 |
in_line = bufBitmap; |
773 |
out_line = bufBitmapRgba; |
774 |
for (y = 0; y < height; y++) |
775 |
{ |
776 |
in = in_line; |
777 |
out = (unsigned int *) out_line; |
778 |
in_line += pitch * vmul; |
779 |
out_line += pitchrgba; |
780 |
for (x = 0; x < width * hmul; x += hmul) |
781 |
{ |
782 |
red = green = blue = 0; |
783 |
o = 0; |
784 |
for (s = 0; s < 3; s++) |
785 |
{ |
786 |
red += filters[rf][s]*in[x+o]; |
787 |
green += filters[gf][s]*in[x+o]; |
788 |
blue += filters[bf][s]*in[x+o]; |
789 |
o += os; |
790 |
} |
791 |
red = red / 65536; |
792 |
green = green / 65536; |
793 |
blue = blue / 65536; |
794 |
*out++ = (green << 24) | (red << 16) | (green << 8) | blue; |
795 |
} |
796 |
} |
797 |
} |
798 |
#endif /* !FIR_FILTER */ |
526 |
|
799 |
|
527 |
xftg->glyph_memory = sizergba + sizeof (XftGlyph); |
800 |
xftg->glyph_memory = sizergba + sizeof (XftGlyph); |
528 |
if (font->format) |
801 |
if (font->format) |