Lines 57-62
Link Here
|
57 |
#include FT_SYNTHESIS_H |
57 |
#include FT_SYNTHESIS_H |
58 |
#endif |
58 |
#endif |
59 |
|
59 |
|
|
|
60 |
#if HAVE_FT_LIBRARY_SETLCDFILTER |
61 |
#include FT_LCD_FILTER_H |
62 |
#endif |
63 |
|
64 |
/* Fontconfig version older than 2.6 didn't have these options */ |
65 |
#ifndef FC_LCD_FILTER |
66 |
#define FC_LCD_FILTER "lcdfilter" |
67 |
#endif |
68 |
/* Some Ubuntu versions defined FC_LCD_FILTER without defining the following */ |
69 |
#ifndef FC_LCD_NONE |
70 |
#define FC_LCD_NONE 0 |
71 |
#define FC_LCD_DEFAULT 1 |
72 |
#define FC_LCD_LIGHT 2 |
73 |
#define FC_LCD_LEGACY 3 |
74 |
#endif |
75 |
|
76 |
/* FreeType version older than 2.3.5(?) didn't have these options */ |
77 |
#ifndef FT_LCD_FILTER_NONE |
78 |
#define FT_LCD_FILTER_NONE 0 |
79 |
#define FT_LCD_FILTER_DEFAULT 1 |
80 |
#define FT_LCD_FILTER_LIGHT 2 |
81 |
#define FT_LCD_FILTER_LEGACY 16 |
82 |
#endif |
83 |
|
60 |
#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) |
84 |
#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) |
61 |
#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) |
85 |
#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) |
62 |
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) |
86 |
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) |
Lines 740-762
Link Here
|
740 |
return CAIRO_STATUS_SUCCESS; |
764 |
return CAIRO_STATUS_SUCCESS; |
741 |
} |
765 |
} |
742 |
|
766 |
|
743 |
/* Empirically-derived subpixel filtering values thanks to Keith |
767 |
/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot |
744 |
* Packard and libXft. */ |
768 |
* into a different format. For example, we want to convert a |
745 |
static const int filters[3][3] = { |
769 |
* FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit |
746 |
/* red */ |
770 |
* ARGB or ABGR bitmap. |
747 |
#if 0 |
771 |
* |
748 |
{ 65538*4/7,65538*2/7,65538*1/7 }, |
772 |
* this function prepares a target descriptor for this operation. |
749 |
/* green */ |
773 |
* |
750 |
{ 65536*1/4, 65536*2/4, 65537*1/4 }, |
774 |
* input :: target bitmap descriptor. The function will set its |
751 |
/* blue */ |
775 |
* 'width', 'rows' and 'pitch' fields, and only these |
752 |
{ 65538*1/7,65538*2/7,65538*4/7 }, |
776 |
* |
|
|
777 |
* slot :: the glyph slot containing the source bitmap. this |
778 |
* function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP |
779 |
* |
780 |
* mode :: the requested final rendering mode. supported values are |
781 |
* MONO, NORMAL (i.e. gray), LCD and LCD_V |
782 |
* |
783 |
* the function returns the size in bytes of the corresponding buffer, |
784 |
* it's up to the caller to allocate the corresponding memory block |
785 |
* before calling _fill_xrender_bitmap |
786 |
* |
787 |
* it also returns -1 in case of error (e.g. incompatible arguments, |
788 |
* like trying to convert a gray bitmap into a monochrome one) |
789 |
*/ |
790 |
static int |
791 |
_compute_xrender_bitmap_size(FT_Bitmap *target, |
792 |
FT_GlyphSlot slot, |
793 |
FT_Render_Mode mode) |
794 |
{ |
795 |
FT_Bitmap *ftbit; |
796 |
int width, height, pitch; |
797 |
|
798 |
if (slot->format != FT_GLYPH_FORMAT_BITMAP) |
799 |
return -1; |
800 |
|
801 |
/* compute the size of the final bitmap */ |
802 |
ftbit = &slot->bitmap; |
803 |
|
804 |
width = ftbit->width; |
805 |
height = ftbit->rows; |
806 |
pitch = (width + 3) & ~3; |
807 |
|
808 |
switch (ftbit->pixel_mode) { |
809 |
case FT_PIXEL_MODE_MONO: |
810 |
if (mode == FT_RENDER_MODE_MONO) { |
811 |
pitch = (((width + 31) & ~31) >> 3); |
812 |
break; |
813 |
} |
814 |
/* fall-through */ |
815 |
|
816 |
case FT_PIXEL_MODE_GRAY: |
817 |
if (mode == FT_RENDER_MODE_LCD || |
818 |
mode == FT_RENDER_MODE_LCD_V) |
819 |
{ |
820 |
/* each pixel is replicated into a 32-bit ARGB value */ |
821 |
pitch = width * 4; |
822 |
} |
823 |
break; |
824 |
|
825 |
case FT_PIXEL_MODE_LCD: |
826 |
if (mode != FT_RENDER_MODE_LCD) |
827 |
return -1; |
828 |
|
829 |
/* horz pixel triplets are packed into 32-bit ARGB values */ |
830 |
width /= 3; |
831 |
pitch = width * 4; |
832 |
break; |
833 |
|
834 |
case FT_PIXEL_MODE_LCD_V: |
835 |
if (mode != FT_RENDER_MODE_LCD_V) |
836 |
return -1; |
837 |
|
838 |
/* vert pixel triplets are packed into 32-bit ARGB values */ |
839 |
height /= 3; |
840 |
pitch = width * 4; |
841 |
break; |
842 |
|
843 |
default: /* unsupported source format */ |
844 |
return -1; |
845 |
} |
846 |
|
847 |
target->width = width; |
848 |
target->rows = height; |
849 |
target->pitch = pitch; |
850 |
target->buffer = NULL; |
851 |
|
852 |
return pitch * height; |
853 |
} |
854 |
|
855 |
/* this functions converts the glyph bitmap found in a FT_GlyphSlot |
856 |
* into a different format (see _compute_xrender_bitmap_size) |
857 |
* |
858 |
* you should call this function after _compute_xrender_bitmap_size |
859 |
* |
860 |
* target :: target bitmap descriptor. Note that its 'buffer' pointer |
861 |
* must point to memory allocated by the caller |
862 |
* |
863 |
* slot :: the glyph slot containing the source bitmap |
864 |
* |
865 |
* mode :: the requested final rendering mode |
866 |
* |
867 |
* bgr :: boolean, set if BGR or VBGR pixel ordering is needed |
868 |
*/ |
869 |
static void |
870 |
_fill_xrender_bitmap(FT_Bitmap *target, |
871 |
FT_GlyphSlot slot, |
872 |
FT_Render_Mode mode, |
873 |
int bgr) |
874 |
{ |
875 |
FT_Bitmap *ftbit = &slot->bitmap; |
876 |
unsigned char *srcLine = ftbit->buffer; |
877 |
unsigned char *dstLine = target->buffer; |
878 |
int src_pitch = ftbit->pitch; |
879 |
int width = target->width; |
880 |
int height = target->rows; |
881 |
int pitch = target->pitch; |
882 |
int subpixel; |
883 |
int h; |
884 |
|
885 |
subpixel = (mode == FT_RENDER_MODE_LCD || |
886 |
mode == FT_RENDER_MODE_LCD_V); |
887 |
|
888 |
if (src_pitch < 0) |
889 |
srcLine -= src_pitch * (ftbit->rows - 1); |
890 |
|
891 |
target->pixel_mode = ftbit->pixel_mode; |
892 |
|
893 |
switch (ftbit->pixel_mode) { |
894 |
case FT_PIXEL_MODE_MONO: |
895 |
if (subpixel) { |
896 |
/* convert mono to ARGB32 values */ |
897 |
|
898 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { |
899 |
int x; |
900 |
|
901 |
for (x = 0; x < width; x++) { |
902 |
if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) |
903 |
((unsigned int *) dstLine)[x] = 0xffffffffU; |
904 |
} |
905 |
} |
906 |
target->pixel_mode = FT_PIXEL_MODE_LCD; |
907 |
|
908 |
} else if (mode == FT_RENDER_MODE_NORMAL) { |
909 |
/* convert mono to 8-bit gray */ |
910 |
|
911 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { |
912 |
int x; |
913 |
|
914 |
for (x = 0; x < width; x++) { |
915 |
if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) |
916 |
dstLine[x] = 0xff; |
917 |
} |
918 |
} |
919 |
target->pixel_mode = FT_PIXEL_MODE_GRAY; |
920 |
|
921 |
} else { |
922 |
/* copy mono to mono */ |
923 |
|
924 |
int bytes = (width + 7) >> 3; |
925 |
|
926 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) |
927 |
memcpy (dstLine, srcLine, bytes); |
928 |
} |
929 |
break; |
930 |
|
931 |
case FT_PIXEL_MODE_GRAY: |
932 |
if (subpixel) { |
933 |
/* convert gray to ARGB32 values */ |
934 |
|
935 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { |
936 |
int x; |
937 |
unsigned int *dst = (unsigned int *) dstLine; |
938 |
|
939 |
for (x = 0; x < width; x++) { |
940 |
unsigned int pix = srcLine[x]; |
941 |
|
942 |
pix |= (pix << 8); |
943 |
pix |= (pix << 16); |
944 |
|
945 |
dst[x] = pix; |
946 |
} |
947 |
} |
948 |
target->pixel_mode = FT_PIXEL_MODE_LCD; |
949 |
} else { |
950 |
/* copy gray into gray */ |
951 |
|
952 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) |
953 |
memcpy (dstLine, srcLine, width); |
954 |
} |
955 |
break; |
956 |
|
957 |
case FT_PIXEL_MODE_LCD: |
958 |
if (!bgr) { |
959 |
/* convert horizontal RGB into ARGB32 */ |
960 |
|
961 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { |
962 |
int x; |
963 |
unsigned char *src = srcLine; |
964 |
unsigned int *dst = (unsigned int *) dstLine; |
965 |
|
966 |
for (x = 0; x < width; x++, src += 3) { |
967 |
unsigned int pix; |
968 |
|
969 |
pix = ((unsigned int)src[0] << 16) | |
970 |
((unsigned int)src[1] << 8) | |
971 |
((unsigned int)src[2] ) | |
972 |
((unsigned int)src[1] << 24) ; |
973 |
|
974 |
dst[x] = pix; |
975 |
} |
976 |
} |
977 |
} else { |
978 |
/* convert horizontal BGR into ARGB32 */ |
979 |
|
980 |
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { |
981 |
|
982 |
int x; |
983 |
unsigned char *src = srcLine; |
984 |
unsigned int *dst = (unsigned int *) dstLine; |
985 |
|
986 |
for (x = 0; x < width; x++, src += 3) { |
987 |
unsigned int pix; |
988 |
|
989 |
pix = ((unsigned int)src[2] << 16) | |
990 |
((unsigned int)src[1] << 8) | |
991 |
((unsigned int)src[0] ) | |
992 |
((unsigned int)src[1] << 24) ; |
993 |
|
994 |
dst[x] = pix; |
995 |
} |
996 |
} |
997 |
} |
998 |
break; |
999 |
|
1000 |
default: /* FT_PIXEL_MODE_LCD_V */ |
1001 |
/* convert vertical RGB into ARGB32 */ |
1002 |
if (!bgr) { |
1003 |
|
1004 |
for (h = height; h > 0; h--, srcLine += 3 * src_pitch, dstLine += pitch) { |
1005 |
int x; |
1006 |
unsigned char* src = srcLine; |
1007 |
unsigned int* dst = (unsigned int *) dstLine; |
1008 |
|
1009 |
for (x = 0; x < width; x++, src += 1) { |
1010 |
unsigned int pix; |
1011 |
#if 1 |
1012 |
pix = ((unsigned int)src[0] << 16) | |
1013 |
((unsigned int)src[src_pitch] << 8) | |
1014 |
((unsigned int)src[src_pitch*2] ) | |
1015 |
0xFF000000 ; |
1016 |
#else |
1017 |
pix = ((unsigned int)src[0] << 16) | |
1018 |
((unsigned int)src[src_pitch] << 8) | |
1019 |
((unsigned int)src[src_pitch*2] ) | |
1020 |
((unsigned int)src[src_pitch] << 24) ; |
753 |
#endif |
1021 |
#endif |
754 |
{ 65538*9/13,65538*3/13,65538*1/13 }, |
1022 |
dst[x] = pix; |
755 |
/* green */ |
1023 |
} |
756 |
{ 65538*1/6, 65538*4/6, 65538*1/6 }, |
1024 |
} |
757 |
/* blue */ |
1025 |
} else { |
758 |
{ 65538*1/13,65538*3/13,65538*9/13 }, |
1026 |
|
759 |
}; |
1027 |
for (h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch) { |
|
|
1028 |
int x; |
1029 |
unsigned char *src = srcLine; |
1030 |
unsigned int *dst = (unsigned int *) dstLine; |
1031 |
|
1032 |
for (x = 0; x < width; x++, src += 1) { |
1033 |
unsigned int pix; |
1034 |
|
1035 |
pix = ((unsigned int)src[src_pitch * 2] << 16) | |
1036 |
((unsigned int)src[src_pitch] << 8) | |
1037 |
((unsigned int)src[0] ) | |
1038 |
((unsigned int)src[src_pitch] << 24) ; |
1039 |
|
1040 |
dst[x] = pix; |
1041 |
} |
1042 |
} |
1043 |
} |
1044 |
} |
1045 |
} |
1046 |
|
760 |
|
1047 |
|
761 |
/* Fills in val->image with an image surface created from @bitmap |
1048 |
/* Fills in val->image with an image surface created from @bitmap |
762 |
*/ |
1049 |
*/ |
Lines 769-775
Link Here
|
769 |
int width, height, stride; |
1056 |
int width, height, stride; |
770 |
unsigned char *data; |
1057 |
unsigned char *data; |
771 |
int format = CAIRO_FORMAT_A8; |
1058 |
int format = CAIRO_FORMAT_A8; |
772 |
cairo_bool_t subpixel = FALSE; |
1059 |
cairo_image_surface_t *image; |
773 |
|
1060 |
|
774 |
width = bitmap->width; |
1061 |
width = bitmap->width; |
775 |
height = bitmap->rows; |
1062 |
height = bitmap->rows; |
Lines 826-836
Link Here
|
826 |
case FT_PIXEL_MODE_LCD: |
1113 |
case FT_PIXEL_MODE_LCD: |
827 |
case FT_PIXEL_MODE_LCD_V: |
1114 |
case FT_PIXEL_MODE_LCD_V: |
828 |
case FT_PIXEL_MODE_GRAY: |
1115 |
case FT_PIXEL_MODE_GRAY: |
829 |
switch (font_options->antialias) { |
1116 |
if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { |
830 |
case CAIRO_ANTIALIAS_DEFAULT: |
|
|
831 |
case CAIRO_ANTIALIAS_GRAY: |
832 |
case CAIRO_ANTIALIAS_NONE: |
833 |
default: |
834 |
stride = bitmap->pitch; |
1117 |
stride = bitmap->pitch; |
835 |
if (own_buffer) { |
1118 |
if (own_buffer) { |
836 |
data = bitmap->buffer; |
1119 |
data = bitmap->buffer; |
Lines 842-945
Link Here
|
842 |
memcpy (data, bitmap->buffer, stride * height); |
1125 |
memcpy (data, bitmap->buffer, stride * height); |
843 |
} |
1126 |
} |
844 |
format = CAIRO_FORMAT_A8; |
1127 |
format = CAIRO_FORMAT_A8; |
845 |
break; |
1128 |
} else { |
846 |
case CAIRO_ANTIALIAS_SUBPIXEL: { |
1129 |
/* if we get there, the data from the source bitmap |
847 |
int x, y; |
1130 |
* really comes from _fill_xrender_bitmap, and is |
848 |
unsigned char *in_line, *out_line, *in; |
1131 |
* made of 32-bit ARGB or ABGR values */ |
849 |
unsigned int *out; |
1132 |
assert (own_buffer != 0); |
850 |
unsigned int red, green, blue; |
1133 |
assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY); |
851 |
int rf, gf, bf; |
|
|
852 |
int s; |
853 |
int o, os; |
854 |
unsigned char *data_rgba; |
855 |
unsigned int width_rgba, stride_rgba; |
856 |
int vmul = 1; |
857 |
int hmul = 1; |
858 |
|
1134 |
|
859 |
switch (font_options->subpixel_order) { |
1135 |
data = bitmap->buffer; |
860 |
case CAIRO_SUBPIXEL_ORDER_DEFAULT: |
|
|
861 |
case CAIRO_SUBPIXEL_ORDER_RGB: |
862 |
case CAIRO_SUBPIXEL_ORDER_BGR: |
863 |
default: |
864 |
width /= 3; |
865 |
hmul = 3; |
866 |
break; |
867 |
case CAIRO_SUBPIXEL_ORDER_VRGB: |
868 |
case CAIRO_SUBPIXEL_ORDER_VBGR: |
869 |
vmul = 3; |
870 |
height /= 3; |
871 |
break; |
872 |
} |
873 |
/* |
874 |
* Filter the glyph to soften the color fringes |
875 |
*/ |
876 |
width_rgba = width; |
877 |
stride = bitmap->pitch; |
1136 |
stride = bitmap->pitch; |
878 |
stride_rgba = (width_rgba * 4 + 3) & ~3; |
|
|
879 |
data_rgba = calloc (stride_rgba, height); |
880 |
if (data_rgba == NULL) { |
881 |
if (own_buffer) |
882 |
free (bitmap->buffer); |
883 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
884 |
} |
885 |
|
886 |
os = 1; |
887 |
switch (font_options->subpixel_order) { |
888 |
case CAIRO_SUBPIXEL_ORDER_VRGB: |
889 |
os = stride; |
890 |
case CAIRO_SUBPIXEL_ORDER_DEFAULT: |
891 |
case CAIRO_SUBPIXEL_ORDER_RGB: |
892 |
default: |
893 |
rf = 0; |
894 |
gf = 1; |
895 |
bf = 2; |
896 |
break; |
897 |
case CAIRO_SUBPIXEL_ORDER_VBGR: |
898 |
os = stride; |
899 |
case CAIRO_SUBPIXEL_ORDER_BGR: |
900 |
bf = 0; |
901 |
gf = 1; |
902 |
rf = 2; |
903 |
break; |
904 |
} |
905 |
in_line = bitmap->buffer; |
906 |
out_line = data_rgba; |
907 |
for (y = 0; y < height; y++) |
908 |
{ |
909 |
in = in_line; |
910 |
out = (unsigned int *) out_line; |
911 |
in_line += stride * vmul; |
912 |
out_line += stride_rgba; |
913 |
for (x = 0; x < width * hmul; x += hmul) |
914 |
{ |
915 |
red = green = blue = 0; |
916 |
o = 0; |
917 |
for (s = 0; s < 3; s++) |
918 |
{ |
919 |
red += filters[rf][s]*in[x+o]; |
920 |
green += filters[gf][s]*in[x+o]; |
921 |
blue += filters[bf][s]*in[x+o]; |
922 |
o += os; |
923 |
} |
924 |
red = red / 65536; |
925 |
green = green / 65536; |
926 |
blue = blue / 65536; |
927 |
*out++ = (green << 24) | (red << 16) | (green << 8) | blue; |
928 |
} |
929 |
} |
930 |
|
931 |
/* Images here are stored in native format. The |
932 |
* backend must convert to its own format as needed |
933 |
*/ |
934 |
|
935 |
if (own_buffer) |
936 |
free (bitmap->buffer); |
937 |
data = data_rgba; |
938 |
stride = stride_rgba; |
939 |
format = CAIRO_FORMAT_ARGB32; |
1137 |
format = CAIRO_FORMAT_ARGB32; |
940 |
subpixel = TRUE; |
|
|
941 |
break; |
942 |
} |
943 |
} |
1138 |
} |
944 |
break; |
1139 |
break; |
945 |
case FT_PIXEL_MODE_GRAY2: |
1140 |
case FT_PIXEL_MODE_GRAY2: |
Lines 951-969
Link Here
|
951 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1146 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
952 |
} |
1147 |
} |
953 |
|
1148 |
|
954 |
*surface = (cairo_image_surface_t *) |
1149 |
/* XXX */ |
|
|
1150 |
*surface = image = (cairo_image_surface_t *) |
955 |
cairo_image_surface_create_for_data (data, |
1151 |
cairo_image_surface_create_for_data (data, |
956 |
format, |
1152 |
format, |
957 |
width, height, stride); |
1153 |
width, height, stride); |
958 |
if ((*surface)->base.status) { |
1154 |
if (image->base.status) { |
959 |
free (data); |
1155 |
free (data); |
960 |
return (*surface)->base.status; |
1156 |
return (*surface)->base.status; |
961 |
} |
1157 |
} |
962 |
|
1158 |
|
963 |
if (subpixel) |
1159 |
if (font_options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) |
964 |
pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE); |
1160 |
pixman_image_set_component_alpha (image->pixman_image, TRUE); |
965 |
|
1161 |
|
966 |
_cairo_image_surface_assume_ownership_of_data ((*surface)); |
1162 |
_cairo_image_surface_assume_ownership_of_data (image); |
967 |
|
1163 |
|
968 |
return CAIRO_STATUS_SUCCESS; |
1164 |
return CAIRO_STATUS_SUCCESS; |
969 |
} |
1165 |
} |
Lines 988-1003
Link Here
|
988 |
cairo_font_options_t *font_options, |
1184 |
cairo_font_options_t *font_options, |
989 |
cairo_image_surface_t **surface) |
1185 |
cairo_image_surface_t **surface) |
990 |
{ |
1186 |
{ |
|
|
1187 |
int rgba = FC_RGBA_UNKNOWN; |
1188 |
int lcd_filter = FT_LCD_FILTER_LEGACY; |
991 |
FT_GlyphSlot glyphslot = face->glyph; |
1189 |
FT_GlyphSlot glyphslot = face->glyph; |
992 |
FT_Outline *outline = &glyphslot->outline; |
1190 |
FT_Outline *outline = &glyphslot->outline; |
993 |
FT_Bitmap bitmap; |
1191 |
FT_Bitmap bitmap; |
994 |
FT_BBox cbox; |
1192 |
FT_BBox cbox; |
995 |
FT_Matrix matrix; |
1193 |
unsigned int width, height; |
996 |
int hmul = 1; |
|
|
997 |
int vmul = 1; |
998 |
unsigned int width, height, stride; |
999 |
cairo_bool_t subpixel = FALSE; |
1000 |
cairo_status_t status; |
1194 |
cairo_status_t status; |
|
|
1195 |
FT_Error fterror; |
1196 |
FT_Library library = glyphslot->library; |
1197 |
FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL; |
1198 |
|
1199 |
switch (font_options->antialias) { |
1200 |
case CAIRO_ANTIALIAS_NONE: |
1201 |
render_mode = FT_RENDER_MODE_MONO; |
1202 |
break; |
1203 |
|
1204 |
case CAIRO_ANTIALIAS_SUBPIXEL: |
1205 |
switch (font_options->subpixel_order) { |
1206 |
case CAIRO_SUBPIXEL_ORDER_DEFAULT: |
1207 |
case CAIRO_SUBPIXEL_ORDER_RGB: |
1208 |
case CAIRO_SUBPIXEL_ORDER_BGR: |
1209 |
render_mode = FT_RENDER_MODE_LCD; |
1210 |
break; |
1211 |
|
1212 |
case CAIRO_SUBPIXEL_ORDER_VRGB: |
1213 |
case CAIRO_SUBPIXEL_ORDER_VBGR: |
1214 |
render_mode = FT_RENDER_MODE_LCD_V; |
1215 |
break; |
1216 |
} |
1217 |
|
1218 |
switch (font_options->lcd_filter) { |
1219 |
case CAIRO_LCD_FILTER_NONE: |
1220 |
lcd_filter = FT_LCD_FILTER_NONE; |
1221 |
break; |
1222 |
case CAIRO_LCD_FILTER_INTRA_PIXEL: |
1223 |
lcd_filter = FT_LCD_FILTER_LEGACY; |
1224 |
break; |
1225 |
case CAIRO_LCD_FILTER_FIR3: |
1226 |
lcd_filter = FT_LCD_FILTER_LIGHT; |
1227 |
break; |
1228 |
case CAIRO_LCD_FILTER_DEFAULT: |
1229 |
case CAIRO_LCD_FILTER_FIR5: |
1230 |
lcd_filter = FT_LCD_FILTER_DEFAULT; |
1231 |
break; |
1232 |
} |
1233 |
|
1234 |
break; |
1235 |
|
1236 |
case CAIRO_ANTIALIAS_DEFAULT: |
1237 |
case CAIRO_ANTIALIAS_GRAY: |
1238 |
render_mode = FT_RENDER_MODE_NORMAL; |
1239 |
} |
1001 |
|
1240 |
|
1002 |
FT_Outline_Get_CBox (outline, &cbox); |
1241 |
FT_Outline_Get_CBox (outline, &cbox); |
1003 |
|
1242 |
|
Lines 1008-1027
Link Here
|
1008 |
|
1247 |
|
1009 |
width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); |
1248 |
width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); |
1010 |
height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); |
1249 |
height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); |
1011 |
stride = (width * hmul + 3) & ~3; |
|
|
1012 |
|
1250 |
|
1013 |
if (width * height == 0) { |
1251 |
if (width * height == 0) { |
1014 |
cairo_format_t format; |
1252 |
cairo_format_t format; |
1015 |
/* Looks like fb handles zero-sized images just fine */ |
1253 |
/* Looks like fb handles zero-sized images just fine */ |
1016 |
switch (font_options->antialias) { |
1254 |
switch (render_mode) { |
1017 |
case CAIRO_ANTIALIAS_NONE: |
1255 |
case FT_RENDER_MODE_MONO: |
1018 |
format = CAIRO_FORMAT_A1; |
1256 |
format = CAIRO_FORMAT_A1; |
1019 |
break; |
1257 |
break; |
1020 |
case CAIRO_ANTIALIAS_SUBPIXEL: |
1258 |
case FT_RENDER_MODE_LCD: |
|
|
1259 |
case FT_RENDER_MODE_LCD_V: |
1021 |
format= CAIRO_FORMAT_ARGB32; |
1260 |
format= CAIRO_FORMAT_ARGB32; |
1022 |
break; |
1261 |
break; |
1023 |
case CAIRO_ANTIALIAS_DEFAULT: |
1262 |
case FT_RENDER_MODE_LIGHT: |
1024 |
case CAIRO_ANTIALIAS_GRAY: |
1263 |
case FT_RENDER_MODE_NORMAL: |
|
|
1264 |
case FT_RENDER_MODE_MAX: |
1025 |
default: |
1265 |
default: |
1026 |
format = CAIRO_FORMAT_A8; |
1266 |
format = CAIRO_FORMAT_A8; |
1027 |
break; |
1267 |
break; |
Lines 1033-1105
Link Here
|
1033 |
return (*surface)->base.status; |
1273 |
return (*surface)->base.status; |
1034 |
} else { |
1274 |
} else { |
1035 |
|
1275 |
|
1036 |
matrix.xx = matrix.yy = 0x10000L; |
1276 |
int bitmap_size; |
1037 |
matrix.xy = matrix.yx = 0; |
|
|
1038 |
|
1277 |
|
1039 |
switch (font_options->antialias) { |
1278 |
switch (render_mode) { |
1040 |
case CAIRO_ANTIALIAS_NONE: |
1279 |
case FT_RENDER_MODE_LCD: |
1041 |
bitmap.pixel_mode = FT_PIXEL_MODE_MONO; |
1280 |
if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) { |
1042 |
bitmap.num_grays = 1; |
1281 |
rgba = FC_RGBA_BGR; |
1043 |
stride = ((width + 31) & -32) >> 3; |
1282 |
} else { |
1044 |
break; |
1283 |
rgba = FC_RGBA_RGB; |
1045 |
case CAIRO_ANTIALIAS_DEFAULT: |
1284 |
} |
1046 |
case CAIRO_ANTIALIAS_GRAY: |
|
|
1047 |
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; |
1048 |
bitmap.num_grays = 256; |
1049 |
stride = (width + 3) & -4; |
1050 |
break; |
1285 |
break; |
1051 |
case CAIRO_ANTIALIAS_SUBPIXEL: |
1286 |
case FT_RENDER_MODE_LCD_V: |
1052 |
switch (font_options->subpixel_order) { |
1287 |
if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) { |
1053 |
case CAIRO_SUBPIXEL_ORDER_RGB: |
1288 |
rgba = FC_RGBA_VBGR; |
1054 |
case CAIRO_SUBPIXEL_ORDER_BGR: |
1289 |
} else { |
1055 |
case CAIRO_SUBPIXEL_ORDER_DEFAULT: |
1290 |
rgba = FC_RGBA_VRGB; |
1056 |
default: |
|
|
1057 |
matrix.xx *= 3; |
1058 |
hmul = 3; |
1059 |
subpixel = TRUE; |
1060 |
break; |
1061 |
case CAIRO_SUBPIXEL_ORDER_VRGB: |
1062 |
case CAIRO_SUBPIXEL_ORDER_VBGR: |
1063 |
matrix.yy *= 3; |
1064 |
vmul = 3; |
1065 |
subpixel = TRUE; |
1066 |
break; |
1067 |
} |
1291 |
} |
1068 |
FT_Outline_Transform (outline, &matrix); |
1292 |
break; |
1069 |
|
1293 |
case FT_RENDER_MODE_MONO: |
1070 |
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; |
1294 |
case FT_RENDER_MODE_LIGHT: |
1071 |
bitmap.num_grays = 256; |
1295 |
case FT_RENDER_MODE_NORMAL: |
1072 |
stride = (width * hmul + 3) & -4; |
1296 |
case FT_RENDER_MODE_MAX: |
|
|
1297 |
default: |
1298 |
break; |
1073 |
} |
1299 |
} |
1074 |
|
1300 |
|
1075 |
bitmap.pitch = stride; |
1301 |
#if HAVE_FT_LIBRARY_SETLCDFILTER |
1076 |
bitmap.width = width * hmul; |
1302 |
FT_Library_SetLcdFilter (library, lcd_filter); |
1077 |
bitmap.rows = height * vmul; |
1303 |
#endif |
1078 |
bitmap.buffer = calloc (stride, bitmap.rows); |
1304 |
|
1079 |
if (bitmap.buffer == NULL) |
1305 |
fterror = FT_Render_Glyph (face->glyph, render_mode); |
|
|
1306 |
|
1307 |
#if HAVE_FT_LIBRARY_SETLCDFILTER |
1308 |
FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE); |
1309 |
#endif |
1310 |
|
1311 |
if (fterror != 0) |
1080 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1312 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1081 |
|
1313 |
|
1082 |
FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul); |
1314 |
bitmap_size = _compute_xrender_bitmap_size (&bitmap, |
|
|
1315 |
face->glyph, |
1316 |
render_mode); |
1317 |
if (bitmap_size < 0) |
1318 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1083 |
|
1319 |
|
1084 |
if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { |
1320 |
bitmap.buffer = calloc (1, bitmap_size); |
1085 |
free (bitmap.buffer); |
1321 |
if (bitmap.buffer == NULL) |
1086 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1322 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1087 |
} |
|
|
1088 |
|
1323 |
|
|
|
1324 |
_fill_xrender_bitmap (&bitmap, face->glyph, render_mode, |
1325 |
(rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR)); |
1326 |
|
1327 |
/* Note: |
1328 |
* _get_bitmap_surface will free bitmap.buffer if there is an error |
1329 |
*/ |
1089 |
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); |
1330 |
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); |
1090 |
if (status) |
1331 |
if (status) |
1091 |
return status; |
1332 |
return status; |
1092 |
} |
|
|
1093 |
|
1333 |
|
1094 |
/* |
1334 |
/* Note: the font's coordinate system is upside down from ours, so the |
1095 |
* Note: the font's coordinate system is upside down from ours, so the |
1335 |
* Y coordinate of the control box needs to be negated. Moreover, device |
1096 |
* Y coordinate of the control box needs to be negated. Moreover, device |
1336 |
* offsets are position of glyph origin relative to top left while xMin |
1097 |
* offsets are position of glyph origin relative to top left while xMin |
1337 |
* and yMax are offsets of top left relative to origin. Another negation. |
1098 |
* and yMax are offsets of top left relative to origin. Another negation. |
1338 |
*/ |
1099 |
*/ |
1339 |
cairo_surface_set_device_offset (&(*surface)->base, |
1100 |
cairo_surface_set_device_offset (&(*surface)->base, |
1340 |
(double)-glyphslot->bitmap_left, |
1101 |
floor (-(double) cbox.xMin / 64.0), |
1341 |
(double)+glyphslot->bitmap_top); |
1102 |
floor (+(double) cbox.yMax / 64.0)); |
1342 |
} |
1103 |
|
1343 |
|
1104 |
return CAIRO_STATUS_SUCCESS; |
1344 |
return CAIRO_STATUS_SUCCESS; |
1105 |
} |
1345 |
} |
Lines 1319-1324
Link Here
|
1319 |
|
1559 |
|
1320 |
if (antialias) { |
1560 |
if (antialias) { |
1321 |
cairo_subpixel_order_t subpixel_order; |
1561 |
cairo_subpixel_order_t subpixel_order; |
|
|
1562 |
int lcd_filter; |
1322 |
|
1563 |
|
1323 |
/* disable hinting if requested */ |
1564 |
/* disable hinting if requested */ |
1324 |
if (FcPatternGetBool (pattern, |
1565 |
if (FcPatternGetBool (pattern, |
Lines 1354-1359
Link Here
|
1354 |
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; |
1595 |
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; |
1355 |
} |
1596 |
} |
1356 |
|
1597 |
|
|
|
1598 |
if (FcPatternGetInteger (pattern, |
1599 |
FC_LCD_FILTER, 0, &lcd_filter) == FcResultMatch) |
1600 |
{ |
1601 |
switch (lcd_filter) { |
1602 |
case FC_LCD_NONE: |
1603 |
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE; |
1604 |
break; |
1605 |
case FC_LCD_DEFAULT: |
1606 |
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5; |
1607 |
break; |
1608 |
case FC_LCD_LIGHT: |
1609 |
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3; |
1610 |
break; |
1611 |
case FC_LCD_LEGACY: |
1612 |
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; |
1613 |
break; |
1614 |
} |
1615 |
} |
1616 |
|
1357 |
#ifdef FC_HINT_STYLE |
1617 |
#ifdef FC_HINT_STYLE |
1358 |
if (FcPatternGetInteger (pattern, |
1618 |
if (FcPatternGetInteger (pattern, |
1359 |
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) |
1619 |
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) |
Lines 1454-1459
Link Here
|
1454 |
if (other->base.hint_style == CAIRO_HINT_STYLE_NONE) |
1714 |
if (other->base.hint_style == CAIRO_HINT_STYLE_NONE) |
1455 |
options->base.hint_style = CAIRO_HINT_STYLE_NONE; |
1715 |
options->base.hint_style = CAIRO_HINT_STYLE_NONE; |
1456 |
|
1716 |
|
|
|
1717 |
if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT) |
1718 |
options->base.lcd_filter = other->base.lcd_filter; |
1719 |
|
1720 |
if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE) |
1721 |
options->base.lcd_filter = CAIRO_LCD_FILTER_NONE; |
1722 |
|
1457 |
if (options->base.antialias == CAIRO_ANTIALIAS_NONE) { |
1723 |
if (options->base.antialias == CAIRO_ANTIALIAS_NONE) { |
1458 |
if (options->base.hint_style == CAIRO_HINT_STYLE_NONE) |
1724 |
if (options->base.hint_style == CAIRO_HINT_STYLE_NONE) |
1459 |
load_flags |= FT_LOAD_NO_HINTING; |
1725 |
load_flags |= FT_LOAD_NO_HINTING; |
Lines 1477-1487
Link Here
|
1477 |
case CAIRO_SUBPIXEL_ORDER_DEFAULT: |
1743 |
case CAIRO_SUBPIXEL_ORDER_DEFAULT: |
1478 |
case CAIRO_SUBPIXEL_ORDER_RGB: |
1744 |
case CAIRO_SUBPIXEL_ORDER_RGB: |
1479 |
case CAIRO_SUBPIXEL_ORDER_BGR: |
1745 |
case CAIRO_SUBPIXEL_ORDER_BGR: |
1480 |
load_target |= FT_LOAD_TARGET_LCD; |
1746 |
load_target = FT_LOAD_TARGET_LCD; |
1481 |
break; |
1747 |
break; |
1482 |
case CAIRO_SUBPIXEL_ORDER_VRGB: |
1748 |
case CAIRO_SUBPIXEL_ORDER_VRGB: |
1483 |
case CAIRO_SUBPIXEL_ORDER_VBGR: |
1749 |
case CAIRO_SUBPIXEL_ORDER_VBGR: |
1484 |
load_target |= FT_LOAD_TARGET_LCD_V; |
1750 |
load_target = FT_LOAD_TARGET_LCD_V; |
1485 |
break; |
1751 |
break; |
1486 |
} |
1752 |
} |
1487 |
} |
1753 |
} |
Lines 2446-2451
Link Here
|
2446 |
} |
2712 |
} |
2447 |
} |
2713 |
} |
2448 |
|
2714 |
|
|
|
2715 |
if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT) |
2716 |
{ |
2717 |
if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch) |
2718 |
{ |
2719 |
int lcd_filter; |
2720 |
|
2721 |
switch (options->lcd_filter) { |
2722 |
case CAIRO_LCD_FILTER_NONE: |
2723 |
lcd_filter = FT_LCD_FILTER_NONE; |
2724 |
break; |
2725 |
case CAIRO_LCD_FILTER_INTRA_PIXEL: |
2726 |
lcd_filter = FT_LCD_FILTER_LEGACY; |
2727 |
break; |
2728 |
case CAIRO_LCD_FILTER_FIR3: |
2729 |
lcd_filter = FT_LCD_FILTER_LIGHT; |
2730 |
break; |
2731 |
default: |
2732 |
case CAIRO_LCD_FILTER_DEFAULT: |
2733 |
case CAIRO_LCD_FILTER_FIR5: |
2734 |
lcd_filter = FT_LCD_FILTER_DEFAULT; |
2735 |
break; |
2736 |
} |
2737 |
|
2738 |
if (! FcPatternAddInteger (pattern, FC_LCD_FILTER, lcd_filter)) |
2739 |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
2740 |
} |
2741 |
} |
2742 |
|
2449 |
if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) |
2743 |
if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) |
2450 |
{ |
2744 |
{ |
2451 |
if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) |
2745 |
if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) |