shared memory: TODO fix client bug
[winnie] / libwinnie / src / text.cc
1 /*
2 winnie - an experimental window system
3
4 Copyright (C) 2013 Eleni Maria Stea
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 Author: Eleni Maria Stea <elene.mst@gmail.com>
20 */
21
22 #include <ft2build.h>
23 #include <freetype/freetype.h>
24
25 #include "gfx.h"
26 #include "shalloc.h"
27 #include "text.h"
28 #include "winnie.h"
29
30 #define DPI 72
31 #define FONT_PATH "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf"
32 #define FONT_SIZE 16
33
34 static int draw_glyph(Pixmap *pixmap, int x, int y, char c);
35
36 struct Text {
37         FT_Library ft_lib;
38         FT_Face ft_face;
39         int text_x, text_y;
40         int text_color[3];
41 };
42
43 static Text *text;
44
45 bool init_text()
46 {
47         if(!(text = (Text*)sh_malloc(sizeof *text))) {
48                 return false;
49         }
50
51         get_subsys()->text_offset = (int)((char*)text - (char*)get_pool());
52
53         if(FT_Init_FreeType(&text->ft_lib)) {
54                 fprintf(stderr, "Failed to initialize the FreeType library!\n");
55                 return false;
56         }
57
58         if(FT_New_Face(text->ft_lib, FONT_PATH, 0, &text->ft_face)) {
59                 fprintf(stderr, "Failed to load font: %s\n", FONT_PATH);
60                 return false;
61         }
62
63         if(FT_Set_Char_Size(text->ft_face, 0, FONT_SIZE * 64, DPI, DPI)) {
64                 fprintf(stderr, "Failed to set font size\n");
65                 return false;
66         }
67
68         set_text_color(255, 255, 255);
69
70         return true;
71 }
72
73 void destroy_text()
74 {
75         sh_free(text);
76 }
77
78 bool client_open_text(void *smem_start, int offset)
79 {
80         text = (Text*)((unsigned char*)smem_start + offset);
81         return true;
82 }
83
84 void client_close_text()
85 {
86 }
87
88 void draw_text(const char *txt, Pixmap *pixmap)
89 {
90         if(!pixmap) {
91                 pixmap = get_framebuffer_pixmap();
92         }
93
94         while(*txt != 0) {
95                 text->text_x += draw_glyph(pixmap, text->text_x, text->text_y, *txt);
96                 txt++;
97         }
98 }
99
100 void set_text_position(int x, int y)
101 {
102         text->text_x = x;
103         text->text_y = y;
104
105 }
106
107 void set_text_color(int r, int g, int b)
108 {
109         text->text_color[0] = r;
110         text->text_color[1] = g;
111         text->text_color[2] = b;
112 }
113
114 static int draw_glyph(Pixmap *pixmap, int x, int y, char c)
115 {
116         if(FT_Load_Char(text->ft_face, c, FT_LOAD_RENDER)) {
117                 return 0;
118         }
119
120         x += text->ft_face->glyph->bitmap_left;
121         y -= text->ft_face->glyph->bitmap_top;
122
123         FT_Bitmap *ft_bmp = &text->ft_face->glyph->bitmap;
124         unsigned char *bmp_ptr = ft_bmp->buffer;
125         unsigned char *pxm_ptr = pixmap->get_image() + (pixmap->get_width() * y + x) * 4;
126
127         Rect clipping_rect = get_clipping_rect();
128
129         for(int i=0; i<ft_bmp->rows; i++) {
130                 int dest_y = i + y;
131                 if(dest_y >= clipping_rect.y + clipping_rect.height) {
132                         break;
133                 }
134
135                 if(dest_y >= clipping_rect.y) {
136                         for(int j=0; j<ft_bmp->width; j++) {
137                                 int dest_x = j + x;
138
139                                 if(dest_x >= clipping_rect.x + clipping_rect.width) {
140                                         break;
141                                 }
142
143                                 if(bmp_ptr[j] && dest_x >= clipping_rect.x) {
144                                         int a = (int)bmp_ptr[j];
145                                         pxm_ptr[4 * j] = (a * text->text_color[0] + pxm_ptr[4 * j] * (255 - a)) / 255;
146                                         pxm_ptr[4 * j + 1] = (a * text->text_color[1] + pxm_ptr[4 * j + 1] * (255 - a)) / 255;
147                                         pxm_ptr[4 * j + 2] = (a * text->text_color[2] + pxm_ptr[4 * j + 2] * (255 - a)) / 255;
148                                 }
149                         }
150                 }
151
152                 pxm_ptr += 4 * pixmap->get_width();
153                 bmp_ptr += ft_bmp->pitch;
154         }
155
156         return text->ft_face->glyph->advance.x >> 6;
157 }