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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
/* 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, const struct libskrift_glyph *glyph1,
const 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, psize;
size_t src_off, dest_off, src_linesize, dest_linesize;
const struct libskrift_glyph *t;
psize = ctx->rendering.smoothing ? 3 : 1;
if (!(glyph1->width | glyph1->height)) {
t = glyph1;
glyph1 = glyph2;
glyph2 = t;
}
if (!(glyph2->width | glyph2->height)) {
size = FLEXSTRUCTSIZE(struct libskrift_glyph, image, glyph1->size);
*glyphp = calloc(1, size);
if (!*glyphp)
return -1;
memcpy(*glyphp, glyph1, size);
return 0;
}
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 = psize;
size *= width = (uint16_t)(x2 - x1);
size *= height = (uint16_t)(y2 - y1);
*glyphp = calloc(1, FLEXSTRUCTSIZE(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;
/* TODO only use merging on actual overlap */
#ifndef OR_MERGE
if (ctx->rendering.smoothing) {
#ifdef SUM_MERGE
unsigned sum;
for (r = src_off = 0; r < glyph2->height; r++, dest_off += dest_linesize, src_off += src_linesize) {
for (c = 0; c < src_linesize; c++) {
sum = (unsigned)(*glyphp)->image[dest_off + c] + (unsigned)glyph2->image[src_off + c];
(*glyphp)->image[dest_off + c] = (uint8_t)(sum | ((sum & 0x100) - 1));
}
}
#else
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]);
#endif
} else {
#endif
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] |= glyph2->image[src_off + c];
#ifndef OR_MERGE
}
#endif
return 0;
}
|