Line data Source code
1 : /*
2 : +----------------------------------------------------------------------+
3 : | For PHP Version 8 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 2015 Elizabeth M Smith |
6 : +----------------------------------------------------------------------+
7 : | http://www.opensource.org/licenses/mit-license.php MIT License |
8 : | Also available in LICENSE |
9 : +----------------------------------------------------------------------+
10 : | Authors: Elizabeth M Smith <auroraeosrose@gmail.com> |
11 : | Swen Zanon <swen.zanon@geoglis.de> |
12 : +----------------------------------------------------------------------+
13 : */
14 :
15 : #ifdef HAVE_CONFIG_H
16 : #include "config.h"
17 : #endif
18 :
19 : #include <cairo.h>
20 : #include <php.h>
21 : #include <zend_exceptions.h>
22 :
23 : #include "php_cairo.h"
24 : #include "php_cairo_internal.h"
25 : #include "ft_font_arginfo.h"
26 :
27 : #if defined(CAIRO_HAS_FT_FONT) && defined(HAVE_FREETYPE)
28 :
29 : php_cairo_ft_error php_cairo_ft_errors[] =
30 : #include FT_ERRORS_H
31 :
32 : #include <fontconfig/fontconfig.h>
33 :
34 :
35 : zend_class_entry *ce_cairo_ftfont;
36 :
37 : /* Functions for stream handling */
38 140 : static unsigned long php_cairo_ft_read_func(
39 : FT_Stream stream,
40 : unsigned long offset,
41 : unsigned char* buffer,
42 : unsigned long count
43 : ) {
44 : stream_closure *closure;
45 140 : closure = (stream_closure *)stream->descriptor.pointer;
46 140 : php_stream_seek(closure->stream, offset, SEEK_SET);
47 140 : return php_stream_read(closure->stream, (char *)buffer, count);
48 : }
49 :
50 2 : static void cairo_user_data_callback_ft_free(pecl_ft_container *ft_container) {
51 2 : if (ft_container->ft_face != NULL) {
52 2 : FT_Done_Face(ft_container->ft_face);
53 : }
54 :
55 2 : if (ft_container->ft_stream != NULL) {
56 2 : pefree(ft_container->ft_stream, 1);
57 : }
58 :
59 2 : if (ft_container->ft_lib != NULL) {
60 2 : FT_Done_FreeType(ft_container->ft_lib);
61 : }
62 :
63 2 : pefree(ft_container, 1);
64 2 : }
65 :
66 3 : static bool php_cairo_create_ft_font_face(
67 : pecl_ft_container *ft_container,
68 : cairo_font_face_object *font_face_object,
69 : php_stream *stream,
70 : bool owned_stream,
71 : int load_flags,
72 : bool throw_exceptions
73 : ) {
74 : FT_Stream ft_stream;
75 : stream_closure *closure;
76 : php_stream_statbuf ssbuf;
77 : FT_Open_Args open_args;
78 : int error;
79 :
80 3 : if (php_stream_stat(stream, &ssbuf) < 0) {
81 0 : return 1;
82 : }
83 :
84 3 : ft_container->ft_face = NULL;
85 3 : ft_container->ft_stream = NULL;
86 :
87 3 : font_face_object->closure = NULL;
88 :
89 3 : closure = ecalloc(1, sizeof(stream_closure));
90 3 : closure->stream = stream;
91 3 : closure->owned_stream = owned_stream;
92 :
93 3 : ft_stream = pecalloc(1, sizeof(*ft_stream), 1);
94 3 : ft_stream->descriptor.pointer = (void *)closure;
95 3 : ft_stream->pos = php_stream_tell(stream);
96 3 : ft_stream->size = ssbuf.sb.st_size;
97 3 : ft_stream->read = php_cairo_ft_read_func;
98 3 : open_args.flags = FT_OPEN_STREAM;
99 3 : open_args.stream = ft_stream;
100 :
101 3 : error = FT_Open_Face(ft_container->ft_lib, &open_args, 0, &ft_container->ft_face);
102 :
103 3 : if (error) {
104 1 : if (owned_stream) {
105 1 : php_stream_close(stream);
106 : }
107 1 : efree(closure);
108 1 : pefree(ft_stream, 1);
109 :
110 1 : return error;
111 : }
112 :
113 2 : font_face_object->closure = closure;
114 :
115 2 : ft_container->ft_stream = ft_stream;
116 2 : font_face_object->font_face = (cairo_font_face_t *)cairo_ft_font_face_create_for_ft_face(ft_container->ft_face, (int)load_flags);
117 :
118 : /* Set Cairo to automatically destroy the FT_Face when the cairo_font_face_t is destroyed */
119 4 : error = cairo_font_face_set_user_data (
120 : font_face_object->font_face,
121 2 : &font_face_object->key,
122 : ft_container,
123 : (cairo_destroy_func_t) cairo_user_data_callback_ft_free
124 : );
125 :
126 :
127 2 : if (error) {
128 0 : cairo_font_face_destroy (font_face_object->font_face);
129 0 : FT_Done_Face(ft_container->ft_face);
130 0 : pefree(ft_stream, 1);
131 0 : return error;
132 : }
133 :
134 2 : return 0;
135 : }
136 :
137 : /* ----------------------------------------------------------------
138 : \Cairo\FontFace\Ft Class API
139 : ------------------------------------------------------------------*/
140 :
141 : /* {{{ proto \Cairo\FontFace\Ft::__construct(string fontFilename, long load_flags)
142 : Creates a new font face for the FreeType font backend from a pre-opened FreeType face. */
143 6 : PHP_METHOD(Cairo_FontFace_Ft, __construct)
144 : {
145 6 : zend_long load_flags = 0;
146 6 : int error = 0;
147 6 : zval *stream_zval = NULL;
148 : cairo_font_face_object *font_face_object;
149 : pecl_ft_container *ft_container;
150 :
151 : php_stream *stream;
152 6 : bool owned_stream = 0;
153 : php_stream_statbuf ssbuf;
154 :
155 6 : ZEND_PARSE_PARAMETERS_START(1, 2)
156 5 : Z_PARAM_ZVAL(stream_zval)
157 5 : Z_PARAM_OPTIONAL
158 6 : Z_PARAM_LONG(load_flags)
159 6 : ZEND_PARSE_PARAMETERS_END();
160 :
161 10 : if (Z_TYPE_P(stream_zval) == IS_STRING) {
162 4 : stream = php_stream_open_wrapper(Z_STRVAL_P(stream_zval), "rb", REPORT_ERRORS, NULL);
163 4 : owned_stream = 1;
164 2 : } else if (Z_TYPE_P(stream_zval) == IS_RESOURCE) {
165 0 : php_stream_from_zval(stream, stream_zval);
166 : } else {
167 1 : zend_throw_exception(ce_cairo_exception,
168 : "Cairo\\FontFace\\Ft::__construct() expects parameter 1 to be a string or a stream resource",
169 : 0
170 : );
171 1 : RETURN_THROWS();
172 : }
173 :
174 4 : if (!stream) {
175 1 : RETURN_NULL();
176 : }
177 :
178 3 : if (php_stream_stat(stream, &ssbuf) != 0) {
179 0 : zend_throw_exception(ce_cairo_exception, "Cannot determine size of stream", 0);
180 0 : RETURN_THROWS();
181 : }
182 :
183 6 : font_face_object = Z_CAIRO_FONT_FACE_P(getThis());
184 3 : if (!font_face_object) {
185 0 : RETURN_NULL();
186 : }
187 :
188 3 : ft_container = pecalloc(1, sizeof(pecl_ft_container), 1);
189 :
190 3 : error = FT_Init_FreeType(&ft_container->ft_lib);
191 3 : if (error) {
192 0 : pefree(ft_container, 1);
193 0 : zend_throw_exception(ce_cairo_exception, "Failed to initalise FreeType library", 0);
194 0 : RETURN_THROWS();
195 : }
196 :
197 3 : error = php_cairo_create_ft_font_face(ft_container, font_face_object, stream, owned_stream, load_flags, 1);
198 :
199 3 : if (error) {
200 1 : const char *err_string = php_cairo_get_ft_error(error);
201 1 : zend_throw_exception_ex(ce_cairo_exception, error,
202 : "Cairo\\FontFace\\Ft::__construct(): An error occurred opening the file %s",
203 : err_string
204 : );
205 1 : pefree(ft_container, 1);
206 1 : RETURN_THROWS();
207 : }
208 :
209 2 : if (php_cairo_throw_exception(cairo_font_face_status(font_face_object->font_face))) {
210 0 : RETURN_THROWS();
211 : }
212 : }
213 : /* }}} */
214 :
215 : /* ----------------------------------------------------------------
216 : \Cairo\FontFace\Ft Definition and registration
217 : ------------------------------------------------------------------*/
218 :
219 : /* {{{ PHP_MINIT_FUNCTION */
220 424 : PHP_MINIT_FUNCTION(cairo_ft_font)
221 : {
222 424 : ce_cairo_ftfont = register_class_Cairo_FontFace_Ft(php_cairo_get_fontface_ce());
223 :
224 424 : return SUCCESS;
225 : }
226 : /* }}} */
227 :
228 : #endif
|