aboutsummaryrefslogtreecommitdiffstats
path: root/libskrift_merge_glyphs.c
blob: 548e8fb075c64bc2db43561b4f02553bf25b3d1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/* See LICENSE file for copyright and license details. */
#include "common.h"

/* TODO How common are grapheme clusters with more than two glyphs? Should we need a variadic version? */

int
libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *ctx, struct libskrift_glyph *glyph1,
                       struct libskrift_glyph *glyph2, struct libskrift_glyph **glyphp)
{
	int16_t x1a, x1b, x2a, x2b, y1a, y1b, y2a, y2b, x1, x2, y1, y2;
	size_t width, height, r, c, size = 1, psize = 1;
	size_t src_off, dest_off, src_linesize, dest_linesize;

	if (ctx->rendering.smoothing == LIBSKRIFT_SUBPIXEL)
		size = psize = 3;

	x1a = glyph1->x;
	x1b = glyph2->x;
	y1a = glyph1->y;
	y1b = glyph2->y;

	x2a = (int16_t)(x1a + (int16_t)glyph1->width);
	x2b = (int16_t)(x1b + (int16_t)glyph2->width);
	y2a = (int16_t)(y1a + (int16_t)glyph1->height);
	y2b = (int16_t)(y1b + (int16_t)glyph2->height);

	x1 = MIN(x1a, x1b);
	y1 = MIN(y1a, y1b);
	x2 = MAX(x2a, x2b);
	y2 = MAX(y2a, y2b);

	size *= width  = (uint16_t)(x2 - x1);
	size *= height = (uint16_t)(y2 - y1);

	*glyphp = calloc(1, offsetof(struct libskrift_glyph, image) + size);
	if (!*glyphp)
		return -1;

	(*glyphp)->advance = glyph1->advance + glyph2->advance;
	(*glyphp)->x       = x1;
	(*glyphp)->y       = y1;
	(*glyphp)->width   = (uint16_t)width;
	(*glyphp)->height  = (uint16_t)height;
	(*glyphp)->size    = size;

	dest_linesize = width * psize;

	src_linesize = glyph1->width * psize;
	dest_off  = (size_t)(glyph1->y - y1) * dest_linesize;
	dest_off += (size_t)(glyph1->x - x1) * psize;
	for (r = src_off = 0; r < glyph1->height; r++, dest_off += dest_linesize, src_off += src_linesize)
		memcpy(&(*glyphp)->image[dest_off], &glyph1->image[src_off], src_linesize);

	src_linesize = glyph2->width * psize;
	dest_off  = (size_t)(glyph2->y - y1) * dest_linesize;
	dest_off += (size_t)(glyph2->x - x1) * psize;
	for (r = src_off = 0; r < glyph2->height; r++, dest_off += dest_linesize, src_off += src_linesize)
		for (c = 0; c < src_linesize; c++)
			(*glyphp)->image[dest_off + c] = MAX((*glyphp)->image[dest_off + c], glyph2->image[src_off + c]);

	return 0;
}