-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathfastchart_text.h
More file actions
103 lines (93 loc) · 4.63 KB
/
Copy pathfastchart_text.h
File metadata and controls
103 lines (93 loc) · 4.63 KB
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
100
101
102
103
/*
+----------------------------------------------------------------------+
| Copyright (c) 2025-2026, Ilia Alshanetsky |
| Copyright (c) 2025-2026, Advanced Internet Designs Inc. |
+----------------------------------------------------------------------+
| This source file is subject to the BSD 3-Clause license that is |
| bundled with this package in the file LICENSE. |
+----------------------------------------------------------------------+
| Author: Ilia Alshanetsky <ilia@ilia.ws> |
+----------------------------------------------------------------------+
*/
#ifndef FASTCHART_TEXT_H
#define FASTCHART_TEXT_H
#include "fastchart_target.h"
typedef enum {
FASTCHART_ALIGN_LEFT = 0,
FASTCHART_ALIGN_CENTER = 1,
FASTCHART_ALIGN_RIGHT = 2,
} fastchart_align;
/* Draw `text` at (x, y) with the given alignment. y is the baseline.
* `text` must be NUL-terminated UTF-8. `color` is a target color
* handle (allocate via fastchart_target_color* on the same target).
* Returns 0 on success, -1 if the font cannot be resolved or used.
* `err_buf` (buf_n bytes) receives a short error string when present. */
int fastchart_text_draw(fastchart_target_t *t,
const char *font_path, double font_size,
int color, int x, int y,
fastchart_align align,
const char *text,
char *err_buf, size_t err_buf_n);
/* Same as fastchart_text_draw but rotates the text counter-clockwise
* by `angle_deg` (typical: 0, 45, 90). The anchor (x, y) is the
* alignment point of the unrotated bounding box. */
int fastchart_text_draw_rotated(fastchart_target_t *t,
const char *font_path, double font_size,
int color, int x, int y,
fastchart_align align, double angle_deg,
const char *text,
char *err_buf, size_t err_buf_n);
/* Measure rendered bounds. *out_w and *out_h are populated on success.
* `t` carries the DPI used during the measurement so the bounds match
* what the corresponding draw call will produce. `t` may be NULL for a
* pure-measure context with no canvas. Returns 0 on success, -1 on
* failure. */
int fastchart_text_measure(fastchart_target_t *t,
const char *font_path, double font_size,
const char *text,
int *out_w, int *out_h,
char *err_buf, size_t err_buf_n);
/* Shared UTF-8 next-codepoint walker for every text consumer
* (measurement, SVG glyph emitter, PDF glyph emitter). One definition
* so the copies cannot drift: an earlier inline copy in the measurer
* SKIPPED invalid bytes (0 width) while the emitters substituted
* U+FFFD with a real advance — layout under-reserved on exactly the
* malformed input the walkers exist to survive. Truncated / invalid
* sequences yield U+FFFD and advance one byte; returns NULL at end. */
static zend_always_inline const unsigned char *fc_utf8_next_cp(
const unsigned char *p, const unsigned char *end, uint32_t *out_cp)
{
if (p >= end) return NULL;
unsigned char c0 = p[0];
if (c0 < 0x80) { *out_cp = c0; return p + 1; }
/* Every following byte must be a 10xxxxxx continuation. Without
* that check a lead byte followed by ASCII (e.g. 0xC2 'A') would be
* folded into one bogus codepoint, swallowing the trailing char and
* desyncing measurement from emission. Reject overlong encodings,
* UTF-16 surrogates, and values above U+10FFFF too; on any invalid
* sequence emit U+FFFD and advance exactly one byte. */
if ((c0 & 0xE0) == 0xC0 && p + 1 < end
&& (p[1] & 0xC0) == 0x80) {
uint32_t cp = ((uint32_t)(c0 & 0x1F) << 6) | (p[1] & 0x3F);
if (cp >= 0x80) { *out_cp = cp; return p + 2; }
} else if ((c0 & 0xF0) == 0xE0 && p + 2 < end
&& (p[1] & 0xC0) == 0x80 && (p[2] & 0xC0) == 0x80) {
uint32_t cp = ((uint32_t)(c0 & 0x0F) << 12)
| ((uint32_t)(p[1] & 0x3F) << 6) | (p[2] & 0x3F);
if (cp >= 0x800 && (cp < 0xD800 || cp > 0xDFFF)) {
*out_cp = cp; return p + 3;
}
} else if ((c0 & 0xF8) == 0xF0 && p + 3 < end
&& (p[1] & 0xC0) == 0x80 && (p[2] & 0xC0) == 0x80
&& (p[3] & 0xC0) == 0x80) {
uint32_t cp = ((uint32_t)(c0 & 0x07) << 18)
| ((uint32_t)(p[1] & 0x3F) << 12)
| ((uint32_t)(p[2] & 0x3F) << 6) | (p[3] & 0x3F);
if (cp >= 0x10000 && cp <= 0x10FFFF) {
*out_cp = cp; return p + 4;
}
}
*out_cp = 0xFFFD;
return p + 1;
}
#endif /* FASTCHART_TEXT_H */