Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
881 theseven 1
#include "global.h"
2
#include "lib/fbconsole/fbconsole.h"
3
#include "interface/console/console.h"
4
#include "interface/framebuffer/framebuffer.h"
5
#include "interface/textrenderer/textrenderer.h"
6
#include "sys/util.h"
7
 
8
 
9
static const uint32_t fbconsole_color[][8] =
10
{
11
    {0x000000, 0xaa0000, 0x00aa00, 0xaa5500, 0x0000aa, 0xaa00aa, 0x00aaaa, 0xaaaaaa},
12
    {0x555555, 0xff5555, 0x55ff55, 0xffff55, 0x5555ff, 0xff55ff, 0x55ffff, 0xffffff},
13
};
14
 
15
static void fbconsole_dirty(const struct console_instance* instance, int x, int y, int w, int h)
16
{
17
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
18
    if (!state->dirty)
19
    {
20
        state->dirty = true;
21
        state->dirty_xs = x;
22
        state->dirty_xe = x + w;
23
        state->dirty_ys = y;
24
        state->dirty_ye = y + h;
25
        return;
26
    }
27
    if (x < state->dirty_xs) state->dirty_xs = x;
28
    if (x + w > state->dirty_xe) state->dirty_xe = x + w;
29
    if (y < state->dirty_ys) state->dirty_ys = y;
30
    if (y + h > state->dirty_ye) state->dirty_ye = y + h;
31
}
32
 
33
static void fbconsole_renderchar(const struct console_instance* instance, int x, int y, char c)
34
{
35
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
36
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
37
    framebuffer_fill(data->fb, data->x + x * state->cwidth, data->y + y * state->cheight, state->cwidth,
38
                     state->cheight, data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);
39
    textrenderer_render_char(data->renderer, data->fb, data->x + x * state->cwidth,
40
                             data->y + y * state->cheight, state->fgcolor, c);
41
    fbconsole_dirty(instance, x, y, 1, 1);
42
}
43
 
44
static void fbconsole_erase_range(const struct console_instance* instance, int x, int y, int w, int h)
45
{
46
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
47
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
48
    framebuffer_fill(data->fb, data->x + x * state->cwidth, data->y + y * state->cheight, w * state->cwidth,
49
                     h * state->cheight, data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);
50
    fbconsole_dirty(instance, x, y, w, h);
51
}
52
 
53
static void fbconsole_clear(const struct console_instance* instance)
54
{
55
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
56
    fbconsole_erase_range(instance, 0, 0, data->w, data->h);
57
}
58
 
59
static void fbconsole_scroll(const struct console_instance* instance, int lines)
60
{
61
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
62
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
63
    if (lines >= data->h || -lines >= data->h) return fbconsole_clear(instance);
64
    if (lines > 0)
65
    {
66
        framebuffer_blit(data->fb, data->x, data->y + lines * state->cheight, data->fb, data->x, data->y,
67
                         data->w * state->cwidth, (data->h - lines) * state->cheight, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);
68
        framebuffer_fill(data->fb, data->x, data->y + (data->h - lines) * state->cheight, data->w * state->cwidth,
69
                         state->cheight * lines, data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);
70
    }
71
    else
72
    {
73
        int y;
74
        for (y = 0; y < data->h + lines; y++)
75
            framebuffer_blit(data->fb, data->x, data->y + y * state->cheight,
76
                             data->fb, data->x, data->y + (y - lines) * state->cheight,
77
                             data->w * state->cwidth, state->cheight, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);
78
        framebuffer_fill(data->fb, data->x, data->y, data->w * state->cwidth, state->cheight * -lines,
79
                         data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);
80
    }
81
    fbconsole_dirty(instance, 0, 0, data->w, data->h);
82
}
83
 
84
static void fbconsole_process_sgr(const struct console_instance* instance, int sgr)
85
{
86
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
87
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
88
    switch (sgr)
89
    {
90
    case 0:
91
        state->bgcolcode = 0;
92
        state->fgcolcode = 7;
93
        state->intensity = 0;
94
        state->inverse = 0;
95
        break;
96
    case 1:
97
        state->intensity = 1;
98
        break;
99
    case 7:
100
        state->inverse = 1;
101
        break;
102
    case 21:
103
        state->intensity = 0;
104
        break;
105
    case 27:
106
        state->inverse = 0;
107
        break;
108
    case 30 ... 37:
109
        state->fgcolcode = sgr - 30;
110
        break;
111
    case 40 ... 47:
112
        state->bgcolcode = sgr - 40;
113
        break;
114
    default:
115
        break;
116
    }
117
    state->fgcolor = framebuffer_color_from_rgb888_be(data->fb->format, fbconsole_color[state->intensity][state->fgcolcode]);
118
    state->bgcolor = framebuffer_color_from_rgb888_be(data->fb->format, fbconsole_color[0][state->bgcolcode]);
119
    if (state->inverse)
120
    {
121
        uint32_t tmp = state->fgcolor;
122
        state->fgcolor = state->bgcolor;
123
        state->bgcolor = tmp;
124
    }
125
}
126
 
127
static void fbconsole_init(const struct console_instance* instance)
128
{
129
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
130
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
131
    textrenderer_init(data->renderer);
132
    state->cwidth = textrenderer_get_max_width(data->renderer);
133
    state->cheight = textrenderer_get_line_height(data->renderer);
134
    state->cpos_x = 0;
135
    state->cpos_y = 0;
136
    state->dirty = false;
137
    state->meta = false;
138
    fbconsole_process_sgr(instance, 0);
139
    fbconsole_clear(instance);
140
}
141
 
142
static int fbconsole_get_width(const struct console_instance* instance)
143
{
144
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
145
    return data->w;
146
}
147
 
148
static int fbconsole_get_height(const struct console_instance* instance)
149
{
150
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
151
    return data->h;
152
}
153
 
154
static void fbconsole_putc(const struct console_instance* instance, char c)
155
{
156
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
157
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
158
 
159
    if (c == 0x1b)
160
    {
161
        state->escape = true;
162
        state->meta = false;
163
        return;
164
    }
165
 
166
    if (state->meta)
167
        switch (c)
168
        {
169
        case '0' ... '9':
170
            if (state->secondarg)
171
            {
172
                state->arg2_present = true;
173
                state->meta_arg2 = state->meta_arg2 * 10 + c - '0';
174
            }
175
            else
176
            {
177
                state->arg1_present = true;
178
                state->meta_arg1 = state->meta_arg1 * 10 + c - '0';
179
            }
180
            return;
181
        case ';':
182
            if (state->secondarg) state->badmeta = true;
183
            else state->secondarg = true;
184
            return;
185
        case 'A' ... 'Z':
186
        case 'a' ... 'z':
187
            state->meta = false;
188
            if (state->badmeta) return;
189
            if (!state->arg1_present) state->meta_arg1 = 1;
190
            if (!state->arg2_present) state->meta_arg2 = 1;
191
            switch (c)
192
            {
193
            case 'A':
194
                state->cpos_y = MAX(0, state->cpos_y - state->meta_arg1 + 1);
195
                break;
196
            case 'B':
197
                state->cpos_y = MIN(data->h, state->cpos_y + state->meta_arg1 - 1);
198
                break;
199
            case 'C':
200
                state->cpos_x = MAX(0, state->cpos_x - state->meta_arg1 + 1);
201
                break;
202
            case 'D':
203
                state->cpos_x = MIN(data->w, state->cpos_x + state->meta_arg1 - 1);
204
                break;
205
            case 'E':
206
                state->cpos_x = 0;
207
                state->cpos_y = MIN(data->h, state->cpos_y + state->meta_arg1 - 1);
208
                break;
209
            case 'F':
210
                state->cpos_x = 0;
211
                state->cpos_y = MAX(0, state->cpos_y - state->meta_arg1 + 1);
212
                break;
213
            case 'G':
214
                state->cpos_x = MAX(0, MIN(data->w, state->meta_arg1 - 1));
215
                break;
216
            case 'H':
217
            case 'f':
218
                state->cpos_x = MAX(0, MIN(data->w, state->meta_arg2 - 1));
219
                state->cpos_y = MAX(0, MIN(data->h, state->meta_arg1 - 1));
220
                break;
221
            case 'J':
222
                if (!state->arg1_present) state->meta_arg1 = 0;
223
                switch (state->meta_arg1)
224
                {
225
                case 0:
226
                    if (state->cpos_y < data->h - 1)
227
                        fbconsole_erase_range(instance, 0, state->cpos_y + 1, data->w, data->h - state->cpos_y - 1);
228
                    if (state->cpos_x < data->w)
229
                        fbconsole_erase_range(instance, state->cpos_x, state->cpos_y, data->w - state->cpos_x, 1);
230
                    break;
231
                case 1:
232
                    if (state->cpos_y) fbconsole_erase_range(instance, 0, 0, data->w, state->cpos_y);
233
                    if (state->cpos_x) fbconsole_erase_range(instance, 0, state->cpos_y, state->cpos_x, 1);
234
                    break;
235
                case 2:
236
                    fbconsole_clear(instance);
237
                    break;
238
                default:
239
                    break;
240
                }
241
                break;
242
            case 'K':
243
                if (!state->arg1_present) state->meta_arg1 = 0;
244
                switch (state->meta_arg1)
245
                {
246
                case 0:
247
                    if (state->cpos_x < data->w)
248
                        fbconsole_erase_range(instance, state->cpos_x, state->cpos_y, data->w - state->cpos_x, 1);
249
                    break;
250
                case 1:
251
                    if (state->cpos_x) fbconsole_erase_range(instance, 0, state->cpos_y, state->cpos_x, 1);
252
                    break;
253
                case 2:
254
                    if (state->cpos_y < data->h)fbconsole_erase_range(instance, 0, state->cpos_y, data->w, 1);
255
                    break;
256
                default:
257
                    break;
258
                }
259
                break;
260
            case 'S':
261
                fbconsole_scroll(instance, state->meta_arg1);
262
                break;
263
            case 'T':
264
                fbconsole_scroll(instance, -state->meta_arg1);
265
                break;
266
            case 'm':
267
                if (!state->arg1_present) state->meta_arg1 = 0;
268
                fbconsole_process_sgr(instance, state->meta_arg1);
269
                if (state->arg2_present) fbconsole_process_sgr(instance, state->meta_arg2);
270
                break;
271
            default:
272
                break;
273
            }
274
            return;
275
        default:
276
            state->meta = false;
277
            break;
278
        }
279
 
280
    if (state->escape && c == '[')
281
    {
282
        state->escape = false;
283
        state->meta = true;
284
        state->badmeta = false;
285
        state->secondarg = false;
286
        state->arg1_present = false;
287
        state->arg2_present = false;
288
        state->meta_arg1 = 0;
289
        state->meta_arg2 = 0;
290
        return;
291
    }
292
    state->escape = false;
293
 
294
    switch (c)
295
    {
296
    case 0x08:  // backspace
297
        if (!state->cpos_x) break;
298
        state->cpos_x--;
299
        fbconsole_renderchar(instance, state->cpos_x, state->cpos_y, ' ');
300
        break;
301
    case 0x0a:  // line feed
302
        state->cpos_x = 0;
303
        state->cpos_y++;
304
        break;
305
    case 0x0c:  // form feed
306
        state->cpos_x = 0;
307
        state->cpos_y = 0;
308
        fbconsole_clear(instance);
309
        break;
310
    case 0x0d:  // carriage return
311
        state->cpos_x = 0;
312
        break;
313
    default:
314
        if (state->cpos_x >= data->w)
315
        {
316
            state->cpos_x = 0;
317
            state->cpos_y++;
318
        }
319
        if (state->cpos_y >= data->h)
320
        {
321
            fbconsole_scroll(instance, state->cpos_y - data->h + 1);
322
            state->cpos_y = data->h - 1;
323
        }
324
        fbconsole_renderchar(instance, state->cpos_x++, state->cpos_y, c);
325
        break;
326
    }
327
}
328
 
329
static void fbconsole_puts(const struct console_instance* instance, const char* str)
330
{
331
    while (*str) fbconsole_putc(instance, *str++);
332
}
333
 
334
static void fbconsole_write(const struct console_instance* instance, const char* buf, int len)
335
{
336
    while (len--) fbconsole_putc(instance, *buf++);
337
}
338
 
339
static void fbconsole_flush(const struct console_instance* instance)
340
{
341
    struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;
342
    struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;
343
    if (!state->dirty) return;
344
    framebuffer_update(data->fb, data->x + state->dirty_xs * state->cwidth, data->y + state->dirty_ys * state->cheight,
345
                       (state->dirty_xe - state->dirty_xs) * state->cwidth, (state->dirty_ye - state->dirty_ys) * state->cheight);
346
    state->dirty = false;
347
}
348
 
349
 
350
const struct console_driver fbconsole_driver =
351
{
352
    .init = fbconsole_init,
353
    .get_width = fbconsole_get_width,
354
    .get_height = fbconsole_get_height,
355
    .putc = fbconsole_putc,
356
    .puts = fbconsole_puts,
357
    .write = fbconsole_write,
358
    .flush = fbconsole_flush,
359
};