source: trunk/third/librsvg/test-ft-gtk.c @ 17277

Revision 17277, 11.4 KB checked in by amb, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17276, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2
3   test-ft-gtk.c: Testbed for freetype/libart integration.
4 
5   Copyright (C) 2000 Eazel, Inc.
6 
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11 
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU General Public
18   License along with this program; if not, write to the
19   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.
21 
22   Author: Raph Levien <raph@artofcode.com>
23*/
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <png.h>
28#include <popt.h>
29#include <math.h>
30#include <sys/time.h>
31#include <unistd.h>
32
33#include <gtk/gtk.h>
34
35#include <gdk-pixbuf/gdk-pixbuf.h>
36
37#include <freetype/freetype.h>
38
39#include <libart_lgpl/art_misc.h>
40#include <libart_lgpl/art_rect.h>
41#include <libart_lgpl/art_alphagamma.h>
42#include <libart_lgpl/art_affine.h>
43#include "art_render.h"
44#include "art_render_mask.h"
45
46#include "rsvg.h"
47#include "rsvg-ft.h"
48
49typedef struct _TestCtx TestCtx;
50
51struct _TestCtx {
52        RsvgFTCtx *ctx;
53        RsvgFTFontHandle fh;
54        int n_lines;
55        char **lines;
56        int y_sp;
57        int y_scroll;
58        GtkWidget *drawingarea;
59        GtkWidget *status;
60        double start_time;
61        gboolean do_drawing;
62        gboolean do_scrolling;
63        gboolean do_invert;
64};
65
66static double
67timing_get_time (void)
68{
69        struct timeval tv;
70        struct timezone tz;
71
72        gettimeofday (&tv, &tz);
73
74        return tv.tv_sec + 1e-6 * tv.tv_usec;
75}
76
77static void invert_glyph (guchar *buf, int rowstride, int width, int height)
78{
79        int x, y;
80        int first;
81        int n_words;
82        int last;
83        guint32 *middle;
84
85        if (width >= 8 && ((rowstride & 3) == 0)) {
86                first = (-(long)buf) & 3;
87                n_words = (width - first) >> 2;
88                last = first + (n_words << 2);
89
90                for (y = 0; y < height; y++) {
91                        middle = (guint32 *)(buf + first);
92                        for (x = 0; x < first; x++)
93                                buf[x] = ~buf[x];
94                        for (x = 0; x < n_words; x++)
95                                middle[x] = ~middle[x];
96                        for (x = last; x < width; x++)
97                                buf[x] = ~buf[x];
98                        buf += rowstride;
99                }
100        } else {
101                for (y = 0; y < height; y++) {
102                        for (x = 0; x < width; x++)
103                                buf[x] = ~buf[x];
104                        buf += rowstride;
105                }
106        }
107}
108
109static void draw_line (TestCtx *ctx, int line_num, ArtIRect *rect)
110{
111        GtkWidget *drawingarea = ctx->drawingarea;
112        int y0;
113        RsvgFTGlyph *glyph;
114        const double affine[6] = { 1, 0, 0, 1, 5, 12 };
115        int glyph_xy[2];
116        ArtIRect line_rect, clear_rect, glyph_rect, draw_rect;
117        int width;
118
119        width = drawingarea->allocation.width;
120
121        y0 = line_num * ctx->y_sp - ctx->y_scroll;
122        if (line_num < 0 || line_num >= ctx->n_lines) {
123                if (ctx->do_drawing) {
124                        gdk_draw_rectangle (drawingarea->window,
125                                            drawingarea->style->white_gc,
126                                            TRUE,
127                                            0, y0, width, ctx->y_sp);
128                }
129        } else {
130                guchar *buf;
131                int rowstride;
132
133                glyph = rsvg_ft_render_string (ctx->ctx, ctx->fh,
134                                               ctx->lines[line_num],
135                                               strlen (ctx->lines[line_num]),
136                                               14, 14,
137                                               affine,
138                                               glyph_xy);
139                rowstride = glyph->rowstride;
140
141                glyph_rect.x0 = glyph_xy[0];
142                glyph_rect.y0 = y0 + glyph_xy[1];
143                glyph_rect.x1 = glyph_rect.x0 + glyph->width;
144                glyph_rect.y1 = glyph_rect.y0 + glyph->height;
145                line_rect.x0 = 0;
146                line_rect.y0 = y0;
147                line_rect.x1 = width;
148                line_rect.y1 = y0 + ctx->y_sp;
149                art_irect_intersect (&clear_rect, rect, &line_rect);
150
151                if (ctx->do_drawing)
152                        gdk_draw_rectangle (drawingarea->window,
153                                            drawingarea->style->white_gc,
154                                            TRUE,
155                                            clear_rect.x0, clear_rect.y0,
156                                            clear_rect.x1 - clear_rect.x0,
157                                            clear_rect.y1 - clear_rect.y0);
158
159                art_irect_intersect (&draw_rect, rect, &glyph_rect);
160                if (!art_irect_empty (&draw_rect) && ctx->do_drawing) {
161                        buf = glyph->buf +
162                                draw_rect.x0 - glyph_rect.x0 +
163                                rowstride * (draw_rect.y0 - glyph_rect.y0);
164                        if (ctx->do_invert) {
165                                invert_glyph (buf, rowstride,
166                                              draw_rect.x1 - draw_rect.x0,
167                                              draw_rect.y1 - draw_rect.y0);
168                        }
169                        gdk_draw_gray_image (drawingarea->window,
170                                             drawingarea->style->white_gc,
171                                             draw_rect.x0, draw_rect.y0,
172                                             draw_rect.x1 - draw_rect.x0,
173                                             draw_rect.y1 - draw_rect.y0,
174                                             GDK_RGB_DITHER_NONE,
175                                             buf,
176                                             rowstride);
177                }
178                rsvg_ft_glyph_unref (glyph);
179        }
180}
181
182static gint
183test_expose (GtkWidget *widget, GdkEventExpose *event, TestCtx *ctx)
184{
185        int line0, line1;
186        int line;
187        ArtIRect rect;
188
189        rect.x0 = event->area.x;
190        rect.y0 = event->area.y;
191        rect.x1 = rect.x0 + event->area.width;
192        rect.y1 = rect.y0 + event->area.height;
193        line0 = (rect.y0 + ctx->y_scroll) / ctx->y_sp;
194        line1 = (rect.y1 + ctx->y_scroll + ctx->y_sp - 1) / ctx->y_sp;
195        for (line = line0; line < line1; line++) {
196#ifdef VERBOSE
197                g_print ("drawing line %d of [%d..%d]\n", line, line0, line1 - 1);
198#endif
199                draw_line (ctx, line, &rect);
200        }
201        return FALSE;
202}
203
204static void
205scroll_to (TestCtx *ctx, int new_y)
206{
207        GtkWidget *drawingarea = ctx->drawingarea;
208        int scroll_amt = new_y - ctx->y_scroll;
209        int width = drawingarea->allocation.width;
210        int height = drawingarea->allocation.height;
211        int y0, y1;
212        GdkEventExpose expose;
213
214        if (scroll_amt == 0)
215                return;
216
217#ifdef VERBOSE
218        g_print ("scrolling to %d\n", new_y);
219#endif
220        if (scroll_amt > 0 && scroll_amt < height) {
221                y0 = height - scroll_amt;
222                y1 = height;
223                if (ctx->do_scrolling) {
224                        gdk_draw_pixmap (drawingarea->window,
225                                         drawingarea->style->white_gc,
226                                         drawingarea->window,
227                                         0, scroll_amt,
228                                         0, 0,
229                                         width, y0);
230                }
231        } else if (scroll_amt < 0 && -scroll_amt < height) {
232                y0 = 0;
233                y1 = -scroll_amt;
234                if (ctx->do_scrolling) {
235                        gdk_draw_pixmap (drawingarea->window,
236                                         drawingarea->style->white_gc,
237                                         drawingarea->window,
238                                         0, 0,
239                                         0, y1,
240                                         width, height - y1);
241                }
242        } else {
243                y0 = 0;
244                y1 = height;
245        }
246        ctx->y_scroll = new_y;
247        expose.area.x = 0;
248        expose.area.width = width;
249        expose.area.y = y0;
250        expose.area.height = y1 - y0;
251        test_expose (drawingarea, &expose, ctx);
252}
253
254static gboolean scroll_idler (gpointer data)
255{
256        TestCtx *ctx = (TestCtx *)data;
257        GtkWidget *drawingarea = ctx->drawingarea;
258        int width = drawingarea->allocation.width;
259        int height = drawingarea->allocation.height;
260
261        if ((ctx->y_scroll + height) < ctx->n_lines * ctx->y_sp) {
262                scroll_to (ctx, ctx->y_scroll + 100);
263                return TRUE;
264        } else {
265                double elapsed;
266                char str[128];
267
268                scroll_to (ctx, 0);
269                elapsed = timing_get_time () - ctx->start_time;
270                sprintf (str, "%g seconds to scroll, %g Mpix/s",
271                         elapsed,
272                         width * ctx->y_sp * ctx->n_lines * 1e-6 / elapsed);
273                gtk_label_set_text (GTK_LABEL (ctx->status), str);
274                return FALSE;
275        }
276}
277
278static void
279check_toggle (GtkWidget *button, int state, gboolean *bool) {
280        *bool = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
281}
282
283static GtkWidget *
284check_button (const char *label, gboolean *bool) {
285        GtkWidget *result;
286
287        result = gtk_check_button_new_with_label (label);
288        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (result), *bool);
289        gtk_signal_connect (GTK_OBJECT (result), "state_changed",
290                            (GtkSignalFunc) check_toggle, bool);
291        return result;
292}
293
294static void
295start_scrolling (GtkWidget *widget, TestCtx *ctx)
296{
297        scroll_to (ctx, 0);
298        gtk_idle_add (scroll_idler, ctx);
299        ctx->start_time = timing_get_time ();
300        gtk_label_set_text (GTK_LABEL (ctx->status), "Scrolling...");
301}
302
303static void
304test_ft_quit (GtkWidget *widget, TestCtx *ctx)
305{
306        rsvg_ft_ctx_done (ctx->ctx);
307        gtk_main_quit ();
308}
309
310static TestCtx *new_test_window (const char *fn, const char *afn,
311                                 int width, int height)
312{
313        GtkWidget *topwin;
314        GtkWidget *vbox;
315        GtkWidget *buttonbar;
316        GtkWidget *button;
317        GtkWidget *drawingarea;
318        TestCtx *ctx;
319
320        ctx = g_new (TestCtx, 1);
321
322        topwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
323        gtk_signal_connect (GTK_OBJECT (topwin), "destroy",
324                            (GtkSignalFunc) test_ft_quit, ctx);
325
326        vbox = gtk_vbox_new (FALSE, 0);
327        gtk_container_add (GTK_CONTAINER (topwin), vbox);
328
329        drawingarea = gtk_drawing_area_new ();
330        gtk_drawing_area_size (GTK_DRAWING_AREA (drawingarea), width, height);
331        gtk_box_pack_start (GTK_BOX (vbox), drawingarea, TRUE, TRUE, 0);
332
333        ctx->ctx = rsvg_ft_ctx_new ();
334        ctx->fh = rsvg_ft_intern (ctx->ctx, fn);
335        if (afn) rsvg_ft_font_attach (ctx->ctx, ctx->fh, afn);
336        ctx->n_lines = 0;
337        ctx->lines = NULL;
338        ctx->y_sp = 16;
339        ctx->y_scroll = 0;
340        ctx->drawingarea = drawingarea;
341
342        ctx->do_drawing = TRUE;
343        ctx->do_scrolling = TRUE;
344        ctx->do_invert = TRUE;
345
346        gtk_signal_connect (GTK_OBJECT (drawingarea), "expose_event",
347                            (GtkSignalFunc) test_expose, ctx);
348
349        buttonbar = gtk_hbox_new (FALSE, 5);
350        gtk_box_pack_start (GTK_BOX (vbox), buttonbar, FALSE, FALSE, 0);
351
352        button = check_button ("Do drawing", &ctx->do_drawing);
353        gtk_container_add (GTK_CONTAINER (buttonbar), button);
354
355        button = check_button ("Do scrolling", &ctx->do_scrolling);
356        gtk_container_add (GTK_CONTAINER (buttonbar), button);
357
358        button = check_button ("Do invert", &ctx->do_invert);
359        gtk_container_add (GTK_CONTAINER (buttonbar), button);
360
361        button = gtk_button_new_with_label ("Start scroll test");
362        gtk_container_add (GTK_CONTAINER (buttonbar), button);
363        gtk_signal_connect (GTK_OBJECT (button), "clicked",
364                            (GtkSignalFunc) start_scrolling, ctx);
365
366        ctx->status = gtk_label_new ("");
367        gtk_box_pack_start (GTK_BOX (vbox), ctx->status, FALSE, FALSE, 2);
368
369        gtk_widget_show_all (topwin);
370
371        return ctx;
372}
373
374static void set_text (TestCtx *ctx, const char *fn) {
375        FILE *f;
376        char line[256];
377        int n_lines;
378        char **lines;
379
380        lines = NULL;
381
382        f = fopen (fn, "r");
383        if (f == NULL) {
384                g_warning ("Error opening file %s\n", fn);
385                return;
386        }
387        n_lines = 0;
388        for (;;) {
389                int len;
390
391                if (fgets (line, sizeof(line), f) == NULL)
392                        break;
393                if (n_lines == 0)
394                        lines = g_new (char *, 1);
395                else if (!(n_lines & (n_lines - 1))) {
396                        lines = g_renew (char *, lines, n_lines << 1);
397                }
398
399                g_assert (lines != NULL);
400
401                len = strlen (line);
402                if (len > 0 && line[len - 1] == '\n')
403                        line[--len] = 0;
404                while (len > 0 && line[len - 1] == '\r')
405                        line[--len] = 0;
406                lines[n_lines++] = g_strdup (line);
407        }
408        fclose (f);
409        ctx->n_lines = n_lines;
410        ctx->lines = lines;
411}
412
413int main(int argc, char **argv)
414{
415        char *zoom_str = "1.0";
416       
417        gint    font_width = 36;
418        gint    font_height = 36;
419        char    *font_file_name = "/usr/share/fonts/default/Type1/n021003l.pfb";
420        char    *add_font_file_name = NULL;
421        char *text_file_name = "rsvg-ft.c";
422
423        poptContext optCtx;
424        struct poptOption optionsTable[] =
425        {
426                {"zoom", 'z', POPT_ARG_STRING, &zoom_str, 0, NULL, "zoom factor"},
427                {"font-width", 'w', POPT_ARG_INT, &font_width, 0, NULL, "Font Width"},
428                {"font-height", 'h', POPT_ARG_INT, &font_height, 0, NULL, "Font Height"},
429                {"font-file-name", 'f', POPT_ARG_STRING, &font_file_name, 0, NULL, "Font File Name"},
430                {"add-font-file-name", 'a', POPT_ARG_STRING, &add_font_file_name, 0, NULL, "Additional Font File Name"},
431                {"text-file-name", 't', POPT_ARG_STRING, &text_file_name, 0, NULL, "Text"},
432                POPT_AUTOHELP {NULL, 0, 0, NULL, 0}
433        };
434        char c;
435        const char *const *args;
436        TestCtx *ctx;
437
438        gtk_init (&argc, &argv);
439
440        gdk_rgb_init ();
441
442        gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
443        gtk_widget_set_default_visual (gdk_rgb_get_visual ());
444
445        optCtx =
446            poptGetContext("test-ft", argc, (const char **) argv,
447                           optionsTable, 0);
448
449        c = poptGetNextOpt(optCtx);
450        args = poptGetArgs(optCtx);
451
452        ctx = new_test_window (font_file_name, add_font_file_name, 640, 480);
453
454        set_text (ctx, text_file_name);
455
456        gtk_main ();
457
458        return 0;
459}
Note: See TracBrowser for help on using the repository browser.