"Fossies" - the Fresh Open Source Software archive

Member "xfstt-1.9/src/showttf.cc" of archive xfstt-1.9.tar.gz:


/*
 * Show glyphs
 *
 * Copyright © 1997-1998 Herbert Duerr
 * Copyright © 2004,2008,2010,2012 Guillem Jover <guillem@hadrons.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Softaware
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "config.h"

#define STARTGLYF	6
#define DEFAULT_FONT	"times.ttf"

#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <X11/keysym.h>
#include <xcb/xcb.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xcb_image.h>

#include "ttf.h"

static Rasterizer *raster;
static uint32_t color[5];
static uint8_t *pixmap;

#define BMPSIZE		1048 * 2048
uint8_t *bitmap = 0;

#define DEFAULT_WIDTH	200
#define DEFAULT_HEIGHT	220

#ifndef MAGNIFY
int MAGNIFY = 1;
#endif /*MAGNIFY*/

struct font_state {
	int size;
	int angle;
	uint16_t width;
	uint16_t height;
	int glyphNo;
};

static void
glyph2image(struct font_state *state, xcb_image_t *img)
{
	int length;
	static int old_size = 0, old_angle = 0;

	if (!bitmap)
		bitmap = (uint8_t *)allocMem(BMPSIZE);
	if (!bitmap)
		return;

	if (state->size != old_size || state->angle != old_angle) {
		old_size = state->size;
		old_angle = state->angle;
		int xcos = (int)(state->size * cos(state->angle * M_PI / 180));
		int xsin = (int)(state->size * sin(state->angle * M_PI / 180));
		raster->setPixelSize(xcos, -xsin, xsin, xcos);
		printf("fontsize = %d, angle = %d\n", state->size, state->angle);
	}

	GlyphMetrics gm;
	length = raster->putGlyphBitmap(state->glyphNo, bitmap, bitmap + BMPSIZE, &gm);
	img->size = length;

	img->width = 0;
	if (length == 0)
		return;

#if 0
	if (raster->anti_aliasing <= 0)
		switch (SCANLINEPAD) {
		case 8:
			break;
		case 16: {
			uint16_t *p = (uint16_t *)bitmap;
			for (int i = length; --i >= 0; ++p)
				*p = bswaps(*p);
			}
			break;
		case 32: {
			uint32_t *p = (uint32_t *)bitmap;
			for (int i = length; --i >= 0; ++p)
				*p = bswapl(*p);
			}
			break;
		case 64: {
			uint32_t *p = (uint32_t *)bitmap;
			for (int i = length; --i >= 0; p += 2) {
					uint32_t tmp = p[0];
					p[0] = bswapl(p[1]);
					p[1] = bswapl(tmp);
				}
			}
			break;
		}
#endif

	if (raster->anti_aliasing > 0)
		for (int i = length; --i >= 0;)
			pixmap[i] = color[bitmap[i]];
#if 0
#ifndef MAGNIFY
	else if (MAGNIFY) {
		int8_t *p1 = (int8_t *)bitmap;
		uint8_t *p2 = pixmap;
		raster->dX *= 8;	// 1 bpp -> 8 bpp
		for (int h = 0; h < raster->height; ++h) {
			int cy = h / MAGNIFY;
			int8_t m;
			for (int w = 0; w < raster->dX; ++w) {
				if ((w & 7) == 0)
					m = *(p1++);
				int c = ((w / MAGNIFY) ^ cy) & 1;
				*(p2++) = color[(m < 0) ? 3 + c : c];
				m <<= 1;
			}
		}
	}
#endif
#endif

	int isPixmap = (MAGNIFY || raster->anti_aliasing > 0);

	img->width = raster->width;
	img->height = raster->height;
	if (isPixmap)
		img->format = XCB_IMAGE_FORMAT_Z_PIXMAP;
	else
		img->format = XCB_IMAGE_FORMAT_XY_BITMAP;
	img->data = (uint8_t *)(isPixmap ? pixmap : bitmap);
	img->byte_order = XCB_IMAGE_ORDER_MSB_FIRST;
	img->unit = 8;
	img->bit_order = XCB_IMAGE_ORDER_MSB_FIRST;
	img->scanline_pad = 0;
	img->depth = isPixmap ? 8 : 1;
	img->stride = raster->dX;
	img->bpp = isPixmap ? 8 : 1;
}

static uint32_t
new_color(xcb_connection_t *c, xcb_colormap_t cmap,
          uint16_t r, uint16_t g, uint16_t b)
{
	xcb_alloc_color_cookie_t cookie;
	xcb_alloc_color_reply_t *reply;
	uint32_t color;

	cookie = xcb_alloc_color(c, cmap, r, g, b);
	reply = xcb_alloc_color_reply(c, cookie, NULL);
	if (!reply)
		return 0;

	color = reply->pixel;
	free(reply);

	return color;
}

xcb_screen_t *
screen_of_display(xcb_connection_t *c, int screen)
{
	xcb_screen_iterator_t iter;

	iter = xcb_setup_roots_iterator(xcb_get_setup(c));
	for (; iter.rem; --screen, xcb_screen_next(&iter))
		if (screen == 0)
			return iter.data;

	return NULL;
}

int
main(int argc, char** argv)
{
	xcb_connection_t *c;
	int screen_nr;
	xcb_screen_t *screen;
	xcb_visualid_t root_visual = { 0 };
	xcb_window_t root_window = { 0 };
	xcb_gcontext_t gc = { 0 };
	xcb_colormap_t cmap = { 0 };
	xcb_key_symbols_t *keysyms;
	uint32_t black, white, yellow;

	if (argc != 2) {
		fprintf(stderr, "Usage: showttf fontfile.ttf\n");
		fprintf(stderr, "use the cursor keys to navigate\n");
		return -1;
	}

	const char *ttFileName = (argc == 2) ? argv[1] : DEFAULT_FONT;

	pixmap = new uint8_t[1024 * 1024];

	int done = 0;

	c = xcb_connect(NULL, &screen_nr);

	screen = screen_of_display(c, screen_nr);
	if (screen == NULL)
		return 1;

	root_visual = screen->root_visual;
	root_window = screen->root;
	cmap = screen->default_colormap;

	gc = xcb_generate_id(c);

	uint32_t mask;
	uint32_t values[5];

	mask |= XCB_GC_FUNCTION;
	values[0] = XCB_GX_COPY;

	mask |= XCB_GC_FOREGROUND;
	values[1] = screen->black_pixel;

	mask |= XCB_GC_BACKGROUND;
	values[2] = screen->white_pixel;

	mask |= XCB_GC_LINE_WIDTH;
	values[3] = 1;

	mask |= XCB_GC_LINE_STYLE;
	values[4] = XCB_LINE_STYLE_SOLID;

	xcb_create_gc(c, gc, root_window, mask, values);

	keysyms = xcb_key_symbols_alloc(c);

	color[0] = new_color(c, cmap, 0xF000, 0xF000, 0xF000);
	color[1] = new_color(c, cmap, 0xB400, 0xB400, 0xB400);
	color[2] = new_color(c, cmap, 0x7800, 0x7800, 0x7800);
	// XXX: color[3] = new_color(c, cmap, 0x3C00, 0x3C00, 0x3C00);
	color[3] = new_color(c, cmap, 0x5000, 0x5000, 0x5000);
	color[4] = new_color(c, cmap, 0x0000, 0x0000, 0x0000);

	white = new_color(c, cmap, 0xF000, 0xF000, 0xF000);
	black = new_color(c, cmap, 0x0000, 0x0000, 0x0000);
	yellow = new_color(c, cmap, 0xFF00, 0xFF00, 0x0000);

	struct font_state state;

	state.width = DEFAULT_WIDTH;
	state.height = DEFAULT_HEIGHT;

#if 0
	int fid = XLoadFont(display, "TTM20_Bitstream Cyberbit");
	XSetFont(display, textGC, fid);
	XChar2b *tststr = (XChar2b *)"\0a\0b\0c\0\x61";
	//char *tststr = "abcd";
#endif

	uint32_t cw_mask = XCB_CW_EVENT_MASK;
	uint32_t cw_values[1] = {
		XCB_EVENT_MASK_KEY_PRESS |
		XCB_EVENT_MASK_KEY_RELEASE |
		XCB_EVENT_MASK_BUTTON_PRESS |
		XCB_EVENT_MASK_BUTTON_RELEASE |
		XCB_EVENT_MASK_EXPOSURE |
		XCB_EVENT_MASK_STRUCTURE_NOTIFY
	};

	xcb_window_t window = xcb_generate_id(c);
	xcb_create_window(c, 0, window, root_window, 0, 0,
	                  state.width, state.height, 1,
	                  XCB_WINDOW_CLASS_INPUT_OUTPUT, root_visual,
	                  cw_mask, cw_values);

	const char title[] = "TrueType Viewer";
	xcb_change_property(c, XCB_PROP_MODE_REPLACE, window,
	                    XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
	                    strlen(title), title);

	xcb_map_window(c, window);
	xcb_flush(c);

	raster = new Rasterizer();
	TTFont *ttFont = new TTFont(ttFileName);
	raster->useTTFont(ttFont);

	state.size = 16;
	state.angle = 0;
	state.glyphNo = STARTGLYF;

	xcb_image_t img;
	xcb_generic_event_t *event;

	while ((event = xcb_wait_for_event(c)) && !done) {
		switch (event->response_type & ~0x80) {
		drawglyph:
#ifndef MAGNIFY
			if (MAGNIFY && fontsize) {
				MAGNIFY = state.height / (state.fontsize + 1);
				if (!MAGNIFY) MAGNIFY = 1;
			}
#endif
		{
			//ttFont->getGlyphNo16(state.glyphNo);
			fprintf(stderr, "gno2 %d\n", state.glyphNo);
			fflush(stderr);
			glyph2image(&state, &img);
		}
			/* fall through */
		case XCB_EXPOSE:
		expose:
		{
			uint32_t gc_values[] = { 0 };

			gc_values[0] = yellow;
			xcb_change_gc(c, gc, XCB_GC_FOREGROUND, gc_values);

			xcb_rectangle_t rect = {
				0, 0, state.width, state.height
			};
			xcb_poly_fill_rectangle(c, window, gc, 1, &rect);

			gc_values[0] = black;
			xcb_change_gc(c, gc, XCB_GC_FOREGROUND, gc_values);

			if (img.width)
				xcb_image_put(c, window, gc, &img, 4, 4, 0);

#if 0
			tststr[3].byte2 = glyphNo;
			tststr[3].byte1 = glyphNo >> 8;
			fprintf(stderr, "glyphNo = %d\n", glyphNo);
			XDrawImageString16(display, win, textGC, 4, 120,
					   tststr, 4);
#endif

			xcb_flush(c);
			break;
		}
		case XCB_KEY_PRESS:
		{
			xcb_key_press_event_t *ev_key;
			xcb_keysym_t ksym;

			ev_key = (xcb_key_press_event_t *)event;

			ksym = xcb_key_press_lookup_keysym(keysyms, ev_key, 0);

			// FIXME: need the keysym name (XLookupString);
//			char keyname[8];

			switch (ksym) {
			case XK_Escape:
				done = 1;
				break;
			case XK_F2:
				raster->grid_fitting = !raster->grid_fitting;
				goto drawglyph;
			case XK_F3:
				raster->anti_aliasing = !raster->anti_aliasing;
				goto drawglyph;
			case XK_F4:
#ifndef MAGNIFY
				MAGNIFY = !MAGNIFY;
#endif /*MAGNIFY*/
				goto drawglyph;
			case XK_Left:
				--state.glyphNo;
				goto drawglyph;
			case XK_Right:
				++state.glyphNo;
				goto drawglyph;
			case XK_Up:
				state.size += 1;
				goto drawglyph;
			case XK_Down:
				state.size -= 1;
				if (state.size < 6)
					state.size = 4;
				goto drawglyph;
			case XK_Page_Up:
				state.size += (state.size >> 2) ? state.size >> 2 : 1;
				goto drawglyph;
			case XK_Page_Down:
				state.size -= (state.size >> 2) ? state.size >> 2 : 1;
				goto drawglyph;
			case XK_Begin:
				state.angle = 0;
				state.size = 8;
#ifndef MAGNIFY
				MAGNIFY = 0;
#endif /*MAGNIFY*/
				goto drawglyph;
			case XK_End:
				state.angle = 0;
				state.size = state.height - 10;
#ifndef MAGNIFY
				MAGNIFY = 0;
#endif /*MAGNIFY*/
				goto drawglyph;
			case XK_Shift_L:
			case XK_Shift_R:
			case XK_Meta_L:
			case XK_Meta_R:
			case XK_Control_L:
			case XK_Control_R:
				goto expose;
			default:
				// XXX: glyphNo = ttFont->getGlyphNo16(0x20AC);

				// FIXME: need keysym name.
				state.glyphNo = ttFont->getGlyphNo16(ksym);
				// printf("key = \"%s\" -> %d\n", keyname, glyphNo);
				printf("key = %c -> %d\n", ksym, state.glyphNo);
				glyph2image(&state, &img);
			}
			goto expose;
		}

		case XCB_CONFIGURE_NOTIFY:
		{
			xcb_configure_notify_event_t *ev_conf;

			ev_conf = (xcb_configure_notify_event_t *)event;

			state.width = ev_conf->width;
			state.height = ev_conf->height;
			goto drawglyph;
			//break;
		}
		case XCB_DESTROY_NOTIFY:
			done = 1;
			break;

		default:
			//printf("XEvent.type = %d\n", event.type);
			break;
		}
	}

	if (bitmap)
		deallocMem(bitmap, BMPSIZE);

	delete raster;
	delete ttFont;
	delete [] pixmap;

	cleanupMem();

	xcb_key_symbols_free(keysyms);
	xcb_unmap_window(c, window);
	xcb_disconnect(c);

	return 0;
}