Line data Source code
1 : /*
2 : +----------------------------------------------------------------------+
3 : | For PHP Version 8.2+ |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Michael Maclean <mgdm@php.net> |
16 : | David MarĂn <davefx@gmail.com> |
17 : | Marcel Bolten <github@marcelbolten.de> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_pango.h"
27 : #include "layout_arginfo.h"
28 :
29 : #include "zend_exceptions.h"
30 :
31 : zend_class_entry *pango_ce_pango_layout;
32 : zend_class_entry *pango_ce_pango_alignment;
33 : zend_class_entry *pango_ce_pango_wrap_mode;
34 : zend_class_entry *pango_ce_pango_ellipsize_mode;
35 :
36 194 : PHP_PANGO_API zend_class_entry* php_pango_get_layout_ce() {
37 194 : return pango_ce_pango_layout;
38 : }
39 :
40 : static zend_object_handlers pango_layout_object_handlers;
41 :
42 343 : pango_layout_object *pango_layout_fetch_object(zend_object *object)
43 : {
44 343 : return (pango_layout_object *) ((char*)(object) - XtOffsetOf(pango_layout_object, std));
45 : }
46 :
47 : /* {{{ Creates a PangoLayout based on the Pango Context object */
48 60 : PHP_METHOD(Pango_Layout, __construct)
49 : {
50 60 : zval *context_zval = NULL;
51 : pango_context_object *context_object;
52 : pango_layout_object *layout_object;
53 :
54 60 : ZEND_PARSE_PARAMETERS_START(1, 1)
55 116 : Z_PARAM_OBJECT_OF_CLASS(context_zval, php_pango_get_context_ce())
56 60 : ZEND_PARSE_PARAMETERS_END();
57 :
58 57 : context_object = Z_PANGO_CONTEXT_P(context_zval);
59 :
60 114 : layout_object = Z_PANGO_LAYOUT_P(getThis());
61 57 : layout_object->layout = pango_layout_new(context_object->context);
62 :
63 57 : if (layout_object->layout == NULL) {
64 0 : zend_throw_exception(
65 : pango_ce_pango_exception,
66 : "Could not create the Pango layout",
67 : 0
68 : );
69 0 : RETURN_THROWS();
70 : }
71 :
72 57 : ZVAL_COPY(&layout_object->pango_context_zv, context_zval);
73 : }
74 : /* }}} */
75 :
76 : /* {{{ Return the PangoContext for the current layout */
77 3 : PHP_METHOD(Pango_Layout, getContext)
78 : {
79 : pango_layout_object *layout_object;
80 : pango_context_object *context_object;
81 : PangoContext *context;
82 :
83 3 : ZEND_PARSE_PARAMETERS_NONE();
84 :
85 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
86 :
87 4 : if (Z_TYPE(layout_object->pango_context_zv) != IS_UNDEF) {
88 2 : ZVAL_COPY(return_value, &layout_object->pango_context_zv);
89 : } else {
90 0 : object_init_ex(return_value, php_pango_get_context_ce());
91 : }
92 :
93 : /* Get the context_object */
94 2 : context_object = Z_PANGO_CONTEXT_P(return_value);
95 : /* Destroy an existing pango context cause we're getting a new one */
96 2 : if (context_object->context != NULL) {
97 2 : g_object_unref(context_object->context);
98 : }
99 :
100 : /* (Re-)Set the internal pango context pointer */
101 2 : context_object->context = pango_layout_get_context(layout_object->layout);
102 2 : g_object_ref(context_object->context);
103 :
104 : // Store the pango context zval in the layout object for later reuse
105 : // ZVAL_COPY(&layout_object->pango_context_zv, return_value);
106 : }
107 : /* }}} */
108 :
109 : /* {{{ Sets the text of the layout. */
110 36 : PHP_METHOD(Pango_Layout, setText)
111 : {
112 : pango_layout_object *layout_object;
113 : char *text;
114 : size_t text_len;
115 :
116 36 : ZEND_PARSE_PARAMETERS_START(1, 1)
117 68 : Z_PARAM_STRING(text, text_len)
118 36 : ZEND_PARSE_PARAMETERS_END();
119 :
120 66 : layout_object = Z_PANGO_LAYOUT_P(getThis());
121 :
122 : // The text will also be truncated on encountering a nul-termination even when length is positive.
123 : // That is problematic as php allows embedded nuls in strings.
124 : // check if text contains a null byte and warn the user
125 33 : if (memchr(text, '\0', text_len) != NULL) {
126 1 : zend_error(E_NOTICE, "Text contains null byte and will be truncated.");
127 : }
128 33 : pango_layout_set_text(layout_object->layout, text, text_len);
129 : }
130 : /* }}} */
131 :
132 : /* {{{ Gets the text currently in the layout */
133 23 : PHP_METHOD(Pango_Layout, getText)
134 : {
135 : pango_layout_object *layout_object;
136 : const char *text;
137 :
138 23 : ZEND_PARSE_PARAMETERS_NONE();
139 :
140 44 : layout_object = Z_PANGO_LAYOUT_P(getThis());
141 22 : if (text = pango_layout_get_text(layout_object->layout)) {
142 44 : RETURN_STRING((char *)text);
143 : }
144 0 : RETURN_EMPTY_STRING();
145 : }
146 : /* }}} */
147 :
148 : /* {{{ Sets the markup of the layout. */
149 13 : PHP_METHOD(Pango_Layout, setMarkup)
150 : {
151 13 : zval *layout_zval = NULL;
152 : pango_layout_object *layout_object;
153 : char *markup;
154 : size_t markup_len;
155 :
156 13 : ZEND_PARSE_PARAMETERS_START(1, 1)
157 22 : Z_PARAM_STRING(markup, markup_len)
158 13 : ZEND_PARSE_PARAMETERS_END();
159 :
160 20 : layout_object = Z_PANGO_LAYOUT_P(getThis());
161 :
162 : // The text may be truncated on encountering a null byte even when length is positive.
163 : // That is problematic as php allows embedded nuls in strings.
164 : // Check if markup contains a null byte and warn the user
165 10 : if (memchr(markup, '\0', markup_len) != NULL) {
166 7 : zend_error(E_NOTICE, "Pango\\Pango::setMarkup(): Markup contains null byte. "
167 : "This may cause the underlying pango markup parser to fail, "
168 : "the text may be truncated, or not be set."
169 : );
170 : }
171 :
172 10 : pango_layout_set_markup(layout_object->layout, markup, markup_len);
173 : }
174 : /* }}} */
175 :
176 : /* {{{ Updates the private PangoContext of a PangoLayout to match the current transformation
177 : and target surface of a Cairo context.
178 : PARAMS ARE REVERSED FROM NATIVE PANGO */
179 2 : PHP_METHOD(Pango_Layout, contextChanged)
180 : {
181 : pango_layout_object *layout_object;
182 :
183 2 : ZEND_PARSE_PARAMETERS_NONE();
184 :
185 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
186 1 : pango_layout_context_changed(layout_object->layout);
187 : }
188 : /* }}} */
189 :
190 : /* {{{ Sets the markup of the layout with accelerator markers. */
191 13 : PHP_METHOD(Pango_Layout, setMarkupWithAccel)
192 : {
193 : pango_layout_object *layout_object;
194 : char *markup;
195 13 : size_t markup_len = 0;
196 : char *accel_marker;
197 13 : size_t accel_marker_len = 0;
198 13 : gunichar first_accel_codepoint = 0;
199 13 : gunichar accel_marker_char = 0;
200 : char first_accel_char[6]; // Max UTF-8 char is 6 bytes
201 : int first_accel_char_len;
202 :
203 13 : ZEND_PARSE_PARAMETERS_START(2, 2)
204 22 : Z_PARAM_STRING(markup, markup_len)
205 20 : Z_PARAM_STRING(accel_marker, accel_marker_len)
206 13 : ZEND_PARSE_PARAMETERS_END();
207 :
208 18 : layout_object = Z_PANGO_LAYOUT_P(getThis());
209 :
210 9 : if (memchr(markup, '\0', markup_len) != NULL) {
211 7 : zend_error(E_NOTICE, "Pango\\Pango::setMarkupWithAccel(): Markup contains null byte. "
212 : "This may cause the underlying pango markup parser to fail, "
213 : "the text may be truncated, or not be set."
214 : );
215 : }
216 :
217 : // Convert UTF-8 string to gunichar
218 9 : if (accel_marker_len > 0) {
219 8 : accel_marker_char = g_utf8_get_char(accel_marker);
220 : }
221 :
222 9 : pango_layout_set_markup_with_accel(
223 : layout_object->layout,
224 : markup,
225 : markup_len,
226 : accel_marker_char,
227 : &first_accel_codepoint
228 : );
229 :
230 9 : if (first_accel_codepoint == 0) {
231 5 : RETURN_EMPTY_STRING();
232 : }
233 :
234 4 : first_accel_char_len = g_unichar_to_utf8(first_accel_codepoint, first_accel_char);
235 8 : RETURN_STRINGL(first_accel_char, first_accel_char_len);
236 : }
237 : /* }}} */
238 :
239 : /* {{{ Gets the width of the layout. */
240 7 : PHP_METHOD(Pango_Layout, getWidth)
241 : {
242 : pango_layout_object *layout_object;
243 : long width;
244 :
245 7 : ZEND_PARSE_PARAMETERS_NONE();
246 :
247 12 : layout_object = Z_PANGO_LAYOUT_P(getThis());
248 6 : width = pango_layout_get_width(layout_object->layout);
249 6 : RETURN_LONG(width);
250 : }
251 : /* }}} */
252 :
253 : /* {{{ Gets the height of the layout. */
254 7 : PHP_METHOD(Pango_Layout, getHeight)
255 : {
256 : pango_layout_object *layout_object;
257 : long height;
258 :
259 7 : ZEND_PARSE_PARAMETERS_NONE();
260 :
261 12 : layout_object = Z_PANGO_LAYOUT_P(getThis());
262 6 : height = pango_layout_get_height(layout_object->layout);
263 6 : RETURN_LONG((zend_long) height);
264 : }
265 : /* }}} */
266 :
267 : /* {{{ Gets the size of the layout. */
268 3 : PHP_METHOD(Pango_Layout, getSize)
269 : {
270 : pango_layout_object *layout_object;
271 3 : int height = 0, width = 0;
272 :
273 3 : ZEND_PARSE_PARAMETERS_NONE();
274 :
275 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
276 2 : if (!layout_object->layout) {
277 0 : RETURN_NULL();
278 : }
279 2 : pango_layout_get_size(layout_object->layout, &width, &height);
280 :
281 : // TODO: don't return an array but an object with properties
282 2 : array_init(return_value);
283 2 : add_assoc_long(return_value, "width", (zend_long) width);
284 2 : add_assoc_long(return_value, "height", (zend_long) height);
285 : }
286 : /* }}} */
287 :
288 : /* {{{ Gets the size of layout in pixels */
289 3 : PHP_METHOD(Pango_Layout, getPixelSize)
290 : {
291 3 : zval *layout_zval = NULL;
292 : pango_layout_object *layout_object;
293 3 : int height = 0, width = 0;
294 :
295 3 : ZEND_PARSE_PARAMETERS_NONE();
296 :
297 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
298 2 : pango_layout_get_pixel_size(layout_object->layout, &width, &height);
299 :
300 : // TODO: don't return an array but an object with properties
301 2 : array_init(return_value);
302 2 : add_assoc_long(return_value, "width", width);
303 2 : add_assoc_long(return_value, "height", height);
304 : }
305 : /* }}} */
306 :
307 : /* {{{ Gets the extents of layout in */
308 3 : PHP_METHOD(Pango_Layout, getExtents)
309 : {
310 : pango_layout_object *layout_object;
311 : PangoRectangle pango_ink_rect;
312 : PangoRectangle pango_logical_rect;
313 : zval ink_rect_zv;
314 : zval logical_rect_zv;
315 :
316 3 : ZEND_PARSE_PARAMETERS_NONE();
317 :
318 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
319 2 : pango_layout_get_extents(layout_object->layout, &pango_ink_rect, &pango_logical_rect);
320 :
321 2 : array_init(return_value);
322 2 : object_init_ex(&ink_rect_zv, php_pango_get_rectangle_ce());
323 2 : *pango_rectangle_object_get_rectangle(&ink_rect_zv) = pango_ink_rect;
324 : add_assoc_zval(return_value, "ink", &ink_rect_zv);
325 :
326 2 : object_init_ex(&logical_rect_zv, php_pango_get_rectangle_ce());
327 2 : *pango_rectangle_object_get_rectangle(&logical_rect_zv) = pango_logical_rect;
328 : add_assoc_zval(return_value, "logical", &logical_rect_zv);
329 : }
330 : /* }}} */
331 :
332 : /* {{{ Gets the extents of layout in pixels */
333 3 : PHP_METHOD(Pango_Layout, getPixelExtents)
334 : {
335 : pango_layout_object *layout_object;
336 : PangoRectangle pango_ink_rect;
337 : PangoRectangle pango_logical_rect;
338 : zval ink_rect_zv;
339 : zval logical_rect_zv;
340 :
341 3 : ZEND_PARSE_PARAMETERS_NONE();
342 :
343 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
344 2 : pango_layout_get_pixel_extents(layout_object->layout, &pango_ink_rect, &pango_logical_rect);
345 :
346 2 : array_init(return_value);
347 2 : object_init_ex(&ink_rect_zv, php_pango_get_rectangle_ce());
348 2 : *pango_rectangle_object_get_rectangle(&ink_rect_zv) = pango_ink_rect;
349 : add_assoc_zval(return_value, "ink", &ink_rect_zv);
350 :
351 2 : object_init_ex(&logical_rect_zv, php_pango_get_rectangle_ce());
352 2 : *pango_rectangle_object_get_rectangle(&logical_rect_zv) = pango_logical_rect;
353 : add_assoc_zval(return_value, "logical", &logical_rect_zv);
354 : }
355 : /* }}} */
356 :
357 : /* {{{ Sets the width of the layout. */
358 10 : PHP_METHOD(Pango_Layout, setWidth)
359 : {
360 : pango_layout_object *layout_object;
361 : zend_long width;
362 :
363 10 : ZEND_PARSE_PARAMETERS_START(1, 1)
364 16 : Z_PARAM_LONG(width)
365 10 : ZEND_PARSE_PARAMETERS_END();
366 :
367 14 : layout_object = Z_PANGO_LAYOUT_P(getThis());
368 7 : pango_layout_set_width(layout_object->layout, width);
369 : }
370 : /* }}} */
371 :
372 : /* {{{ Sets the height of the layout. */
373 8 : PHP_METHOD(Pango_Layout, setHeight)
374 : {
375 : pango_layout_object *layout_object;
376 : zend_long height;
377 :
378 8 : ZEND_PARSE_PARAMETERS_START(1, 1)
379 12 : Z_PARAM_LONG(height)
380 8 : ZEND_PARSE_PARAMETERS_END();
381 :
382 10 : layout_object = Z_PANGO_LAYOUT_P(getThis());
383 5 : pango_layout_set_height(layout_object->layout, height);
384 : }
385 : /* }}} */
386 :
387 : /* {{{ Sets the font_description of the layout. */
388 4 : PHP_METHOD(Pango_Layout, setFontDescription)
389 : {
390 4 : zval *font_desc_zv = NULL;
391 : pango_layout_object *layout_object;
392 : pango_font_description_object *font_description_object;
393 :
394 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
395 4 : Z_PARAM_OBJECT_OF_CLASS(font_desc_zv, php_pango_get_font_description_ce())
396 4 : ZEND_PARSE_PARAMETERS_END();
397 :
398 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
399 1 : font_description_object = Z_PANGO_FONT_DESC_P(font_desc_zv);
400 1 : pango_layout_set_font_description(layout_object->layout, font_description_object->font_description);
401 : }
402 : /* }}} */
403 :
404 : /* {{{ Gets the font_description of the layout. */
405 4 : PHP_METHOD(Pango_Layout, getFontDescription)
406 : {
407 : pango_layout_object *layout_object;
408 4 : pango_font_description_object *font_description_object = NULL;
409 4 : const PangoFontDescription *font_description = NULL;
410 :
411 4 : ZEND_PARSE_PARAMETERS_NONE();
412 :
413 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
414 :
415 : // font_description can be NULL, in that case the font description is from the context and not set on the layout
416 3 : if (!(font_description = pango_layout_get_font_description(layout_object->layout))) {
417 : // TODO: should the font description of the context be returned instead?
418 2 : RETURN_NULL();
419 : }
420 :
421 1 : object_init_ex(return_value, php_pango_get_font_description_ce());
422 1 : font_description_object = Z_PANGO_FONT_DESC_P(return_value);
423 1 : font_description_object->font_description = pango_font_description_copy(font_description);
424 : }
425 : /* }}} */
426 :
427 : /* {{{ Sets whether each line should be justified. */
428 5 : PHP_METHOD(Pango_Layout, setJustify)
429 : {
430 : pango_layout_object *layout_object;
431 : bool justify;
432 :
433 5 : ZEND_PARSE_PARAMETERS_START(1, 1)
434 8 : Z_PARAM_BOOL(justify)
435 5 : ZEND_PARSE_PARAMETERS_END();
436 :
437 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
438 3 : pango_layout_set_justify(layout_object->layout, justify);
439 : }
440 : /* }}} */
441 :
442 : /* {{{ Returns whether text will be justified or not in the current layout */
443 3 : PHP_METHOD(Pango_Layout, getJustify)
444 : { pango_layout_object *layout_object;
445 :
446 3 : ZEND_PARSE_PARAMETERS_NONE();
447 :
448 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
449 2 : RETURN_BOOL(pango_layout_get_justify(layout_object->layout));
450 : }
451 : /* }}} */
452 :
453 : /* {{{ Sets whether each line should be justified. */
454 4 : PHP_METHOD(Pango_Layout, setAlignment)
455 : {
456 : pango_layout_object *layout_object;
457 : zend_object *alignment;
458 :
459 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
460 4 : Z_PARAM_OBJ_OF_CLASS(alignment, pango_ce_pango_alignment)
461 4 : ZEND_PARSE_PARAMETERS_END();
462 :
463 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
464 1 : pango_layout_set_alignment(
465 : layout_object->layout,
466 2 : Z_LVAL_P(zend_enum_fetch_case_value(alignment))
467 : );
468 : }
469 : /* }}} */
470 :
471 : /* {{{ Returns whether text will be justified or not in the current layout */
472 4 : PHP_METHOD(Pango_Layout, getAlignment)
473 : {
474 : pango_layout_object *layout_object;
475 : zend_object *alignment_case;
476 :
477 4 : ZEND_PARSE_PARAMETERS_NONE();
478 :
479 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
480 :
481 3 : zend_enum_get_case_by_value(
482 : &alignment_case, pango_ce_pango_alignment,
483 3 : pango_layout_get_alignment(layout_object->layout),
484 : NULL, false
485 : );
486 :
487 6 : RETURN_OBJ_COPY(alignment_case);
488 : }
489 : /* }}} */
490 :
491 : /* {{{ Sets how each line should be wrapped. */
492 4 : PHP_METHOD(Pango_Layout, setWrap)
493 : {
494 : pango_layout_object *layout_object;
495 : zend_object *wrap;
496 :
497 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
498 4 : Z_PARAM_OBJ_OF_CLASS(wrap, pango_ce_pango_wrap_mode)
499 4 : ZEND_PARSE_PARAMETERS_END();
500 :
501 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
502 1 : pango_layout_set_wrap(
503 : layout_object->layout,
504 2 : Z_LVAL_P(zend_enum_fetch_case_value(wrap))
505 : );
506 : }
507 : /* }}} */
508 :
509 : /* {{{ Returns how text will be wrapped or not in the current layout. */
510 4 : PHP_METHOD(Pango_Layout, getWrap)
511 : {
512 : pango_layout_object *layout_object;
513 : zend_object *wrap_case;
514 :
515 4 : ZEND_PARSE_PARAMETERS_NONE();
516 :
517 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
518 3 : zend_enum_get_case_by_value(
519 : &wrap_case, pango_ce_pango_wrap_mode,
520 3 : pango_layout_get_wrap(layout_object->layout),
521 : NULL, false
522 : );
523 :
524 6 : RETURN_OBJ_COPY(wrap_case);
525 : }
526 : /* }}} */
527 :
528 : /* {{{ Queries whether the layout had to wrap any paragraphs. */
529 2 : PHP_METHOD(Pango_Layout, isWrapped)
530 : {
531 : pango_layout_object *layout_object;
532 :
533 2 : ZEND_PARSE_PARAMETERS_NONE();
534 :
535 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
536 1 : RETURN_BOOL(pango_layout_is_wrapped(layout_object->layout));
537 : }
538 : /* }}} */
539 :
540 : /* {{{ Sets how far each paragraph should be indented. */
541 5 : PHP_METHOD(Pango_Layout, setIndent)
542 : {
543 : pango_layout_object *layout_object;
544 : long indent;
545 :
546 5 : ZEND_PARSE_PARAMETERS_START(1, 1)
547 6 : Z_PARAM_LONG(indent)
548 5 : ZEND_PARSE_PARAMETERS_END();
549 :
550 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
551 2 : pango_layout_set_indent(layout_object->layout, indent);
552 : }
553 : /* }}} */
554 :
555 : /* {{{ Returns how text will be indented or not in the current layout */
556 5 : PHP_METHOD(Pango_Layout, getIndent)
557 : {
558 : pango_layout_object *layout_object;
559 :
560 5 : ZEND_PARSE_PARAMETERS_NONE();
561 :
562 8 : layout_object = Z_PANGO_LAYOUT_P(getThis());
563 4 : RETURN_LONG(pango_layout_get_indent(layout_object->layout));
564 : }
565 : /* }}} */
566 :
567 : /* {{{ Sets the line spacing for the paragraph */
568 4 : PHP_METHOD(Pango_Layout, setSpacing)
569 : {
570 : pango_layout_object *layout_object;
571 : long spacing;
572 :
573 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
574 4 : Z_PARAM_LONG(spacing)
575 4 : ZEND_PARSE_PARAMETERS_END();
576 :
577 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
578 1 : pango_layout_set_spacing(layout_object->layout, spacing);
579 : }
580 : /* }}} */
581 :
582 : /* {{{ Returns the spacing for the current layout */
583 4 : PHP_METHOD(Pango_Layout, getSpacing)
584 : {
585 : pango_layout_object *layout_object;
586 :
587 4 : ZEND_PARSE_PARAMETERS_NONE();
588 :
589 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
590 3 : RETURN_LONG(pango_layout_get_spacing(layout_object->layout));
591 : }
592 : /* }}} */
593 :
594 : /* {{{ Sets the ellipsize mode for the layout */
595 4 : PHP_METHOD(Pango_Layout, setEllipsize)
596 : {
597 : pango_layout_object *layout_object;
598 : zend_object *ellipsize;
599 :
600 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
601 4 : Z_PARAM_OBJ_OF_CLASS(ellipsize, pango_ce_pango_ellipsize_mode)
602 4 : ZEND_PARSE_PARAMETERS_END();
603 :
604 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
605 1 : pango_layout_set_ellipsize(
606 : layout_object->layout,
607 2 : Z_LVAL_P(zend_enum_fetch_case_value(ellipsize))
608 : );
609 : }
610 : /* }}} */
611 :
612 : /* {{{ Returns the ellipsize for the current layout */
613 4 : PHP_METHOD(Pango_Layout, getEllipsize)
614 : {
615 : pango_layout_object *layout_object;
616 : zend_object *ellipsize_case;
617 :
618 4 : ZEND_PARSE_PARAMETERS_NONE();
619 :
620 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
621 3 : zend_enum_get_case_by_value(
622 : &ellipsize_case, pango_ce_pango_ellipsize_mode,
623 3 : pango_layout_get_ellipsize(layout_object->layout),
624 : NULL, false
625 : );
626 :
627 6 : RETURN_OBJ_COPY(ellipsize_case);
628 : }
629 : /* }}} */
630 :
631 : /* {{{ Queries whether the layout had to ellipsize any paragraphs */
632 2 : PHP_METHOD(Pango_Layout, isEllipsized)
633 : {
634 : pango_layout_object *layout_object;
635 :
636 2 : ZEND_PARSE_PARAMETERS_NONE();
637 :
638 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
639 1 : RETURN_BOOL(pango_layout_is_ellipsized(layout_object->layout));
640 : }
641 : /* }}} */
642 :
643 : /* {{{ Returns an array of LayoutLines representing each line of the layout */
644 6 : PHP_METHOD(Pango_Layout, getLines)
645 : {
646 : zval *layout;
647 : pango_layout_object *layout_object;
648 : GSList *lines;
649 : GSList *iter;
650 : zval line_zv;
651 : pango_layout_line_object *line_object;
652 :
653 6 : ZEND_PARSE_PARAMETERS_NONE();
654 :
655 10 : layout = getThis();
656 5 : layout_object = Z_PANGO_LAYOUT_P(layout);
657 : // Todo: Check if there is always be at least one line, even for empty text
658 5 : if (!(lines = pango_layout_get_lines(layout_object->layout))) {
659 0 : RETURN_EMPTY_ARRAY();
660 : }
661 :
662 5 : array_init(return_value);
663 20 : for (iter = lines; iter != NULL; iter = iter->next) {
664 15 : object_init_ex(&line_zv, php_pango_get_layout_line_ce());
665 15 : line_object = Z_PANGO_LAYOUT_LINE_P(&line_zv);
666 15 : line_object->line = pango_layout_line_ref((PangoLayoutLine *)iter->data);
667 15 : ZVAL_COPY(&line_object->layout_zval, layout);
668 :
669 : add_next_index_zval(return_value, &line_zv);
670 : }
671 : }
672 : /* }}} */
673 :
674 : /* {{{ Returns an array of LayoutLines representing each line of the layout */
675 11 : PHP_METHOD(Pango_Layout, getLinesReadonly)
676 : {
677 : zval *layout;
678 : pango_layout_object *layout_object;
679 : GSList *lines;
680 : GSList *iter;
681 : zval line_zv;
682 : pango_layout_line_object *line_object;
683 :
684 11 : ZEND_PARSE_PARAMETERS_NONE();
685 :
686 20 : layout = getThis();
687 10 : layout_object = Z_PANGO_LAYOUT_P(layout);
688 : // Todo: Check if there is always be at least one line, even for empty text
689 10 : if (!(lines = pango_layout_get_lines_readonly(layout_object->layout))) {
690 0 : RETURN_EMPTY_ARRAY();
691 : }
692 :
693 10 : array_init(return_value);
694 22 : for (iter = lines; iter != NULL; iter = iter->next) {
695 12 : object_init_ex(&line_zv, php_pango_get_layout_line_ce());
696 12 : line_object = Z_PANGO_LAYOUT_LINE_P(&line_zv);
697 12 : line_object->line = pango_layout_line_ref((PangoLayoutLine *)iter->data);
698 12 : ZVAL_COPY(&line_object->layout_zval, layout);
699 :
700 : add_next_index_zval(return_value, &line_zv);
701 : }
702 : }
703 : /* }}} */
704 :
705 : /* {{{ Returns a particular LayoutLine from the layout */
706 5 : PHP_METHOD(Pango_Layout, getLine)
707 : {
708 : zval *layout;
709 : pango_layout_object *layout_object;
710 5 : zend_long line_number = 0;
711 : PangoLayoutLine *layout_line;
712 : pango_layout_line_object *layout_line_object;
713 :
714 5 : ZEND_PARSE_PARAMETERS_START(1, 1)
715 6 : Z_PARAM_LONG(line_number)
716 5 : ZEND_PARSE_PARAMETERS_END();
717 :
718 4 : layout = getThis();
719 2 : layout_object = Z_PANGO_LAYOUT_P(layout);
720 :
721 2 : if (!(layout_line = pango_layout_get_line(layout_object->layout, (int) line_number))) {
722 0 : RETURN_NULL();
723 : }
724 :
725 2 : object_init_ex(return_value, php_pango_get_layout_line_ce());
726 2 : layout_line_object = Z_PANGO_LAYOUT_LINE_P(return_value);
727 2 : layout_line_object->line = pango_layout_line_ref(layout_line);
728 2 : ZVAL_COPY(&layout_line_object->layout_zval, layout);
729 : }
730 :
731 : /* {{{ Returns a particular LayoutLine from the layout */
732 19 : PHP_METHOD(Pango_Layout, getLineReadonly)
733 : {
734 : zval *layout;
735 : pango_layout_object *layout_object;
736 19 : zend_long line_number = 0;
737 : PangoLayoutLine *layout_line;
738 : pango_layout_line_object *layout_line_object;
739 :
740 19 : ZEND_PARSE_PARAMETERS_START(1, 1)
741 34 : Z_PARAM_LONG(line_number)
742 19 : ZEND_PARSE_PARAMETERS_END();
743 :
744 32 : layout = getThis();
745 16 : layout_object = Z_PANGO_LAYOUT_P(layout);
746 :
747 16 : if (!(layout_line = pango_layout_get_line_readonly(layout_object->layout, (int) line_number))) {
748 0 : RETURN_NULL();
749 : }
750 :
751 16 : object_init_ex(return_value, php_pango_get_layout_line_ce());
752 16 : layout_line_object = Z_PANGO_LAYOUT_LINE_P(return_value);
753 16 : layout_line_object->line = pango_layout_line_ref(layout_line);
754 16 : ZVAL_COPY(&layout_line_object->layout_zval, layout);
755 : }
756 :
757 : /* {{{ Returns the number of LayoutLines in the layout */
758 5 : PHP_METHOD(Pango_Layout, getLineCount)
759 : {
760 5 : zval *elem = NULL;
761 : pango_layout_object *layout_object;
762 : pango_layout_line_object *layout_line_object;
763 :
764 5 : ZEND_PARSE_PARAMETERS_NONE();
765 :
766 8 : layout_object = Z_PANGO_LAYOUT_P(getThis());
767 4 : RETURN_LONG(pango_layout_get_line_count(layout_object->layout));
768 : }
769 : /* }}} */
770 :
771 : #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 50, 0)
772 : /* {{{ The intended use of this function is testing, benchmarking and debugging. The format is not meant as a permanent storage format. */
773 4 : PHP_METHOD(Pango_Layout, serialize)
774 : {
775 4 : zend_long flags = PANGO_LAYOUT_SERIALIZE_DEFAULT;
776 : pango_layout_object *layout_object;
777 : GBytes* serialized_layout;
778 : const char *text;
779 :
780 4 : ZEND_PARSE_PARAMETERS_START(0, 1);
781 3 : Z_PARAM_OPTIONAL
782 5 : Z_PARAM_LONG(flags)
783 4 : ZEND_PARSE_PARAMETERS_END();
784 :
785 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
786 2 : if (!layout_object->layout) {
787 0 : RETURN_NULL();
788 : }
789 2 : if (serialized_layout = pango_layout_serialize(layout_object->layout, flags)) {
790 2 : text = g_bytes_get_data(serialized_layout, NULL);
791 4 : RETURN_STRING(text);
792 : }
793 :
794 0 : RETURN_EMPTY_STRING();
795 : }
796 : /* }}} */
797 : #endif
798 :
799 : /* {{{ Gets the Y position of baseline of the first line in layout.*/
800 2 : PHP_METHOD(Pango_Layout, getBaseline)
801 : {
802 : pango_layout_object *layout_object;
803 :
804 2 : ZEND_PARSE_PARAMETERS_NONE();
805 :
806 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
807 1 : RETURN_LONG(pango_layout_get_baseline(layout_object->layout));
808 : }
809 : /* }}} */
810 :
811 : /* {{{ Gets whether to calculate the base direction for the layout according to its contents. */
812 4 : PHP_METHOD(Pango_Layout, getAutoDir)
813 : {
814 : pango_layout_object *layout_object;
815 :
816 4 : ZEND_PARSE_PARAMETERS_NONE();
817 :
818 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
819 3 : RETURN_BOOL(pango_layout_get_auto_dir(layout_object->layout));
820 : }
821 : /* }}} */
822 :
823 : /* {{{ Sets whether to calculate the base direction for the layout according to its contents. */
824 5 : PHP_METHOD(Pango_Layout, setAutoDir)
825 : {
826 : pango_layout_object *layout_object;
827 : bool auto_dir;
828 :
829 5 : ZEND_PARSE_PARAMETERS_START(1, 1);
830 6 : Z_PARAM_BOOL(auto_dir)
831 5 : ZEND_PARSE_PARAMETERS_END();
832 :
833 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
834 2 : pango_layout_set_auto_dir(layout_object->layout, auto_dir);
835 : }
836 : /* }}} */
837 :
838 : /* {{{ */
839 2 : PHP_METHOD(Pango_Layout, getCharacterCount)
840 : {
841 : pango_layout_object *layout_object;
842 :
843 2 : ZEND_PARSE_PARAMETERS_NONE();
844 :
845 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
846 1 : RETURN_LONG(pango_layout_get_character_count(layout_object->layout));
847 : }
848 : /* }}} */
849 :
850 : #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 46, 0)
851 : /* {{{ Gets the text direction at the given character position in layout. */
852 4 : PHP_METHOD(Pango_Layout, getDirection)
853 : {
854 : pango_layout_object *layout_object;
855 : zend_long byte_index;
856 : zend_object *direction_case;
857 :
858 4 : ZEND_PARSE_PARAMETERS_START(1, 1);
859 4 : Z_PARAM_LONG(byte_index)
860 4 : ZEND_PARSE_PARAMETERS_END();
861 :
862 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
863 1 : zend_enum_get_case_by_value(
864 : &direction_case, php_pango_get_direction_ce(),
865 1 : pango_layout_get_direction(layout_object->layout, byte_index),
866 : NULL, false
867 : );
868 :
869 2 : RETURN_OBJ_COPY(direction_case);
870 : }
871 : /* }}} */
872 : #endif
873 :
874 : #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 50, 0)
875 : /* {{{ Gets whether the last line should be stretched to fill the entire width of the layout. */
876 4 : PHP_METHOD(Pango_Layout, getJustifyLastLine)
877 : {
878 : pango_layout_object *layout_object;
879 :
880 4 : ZEND_PARSE_PARAMETERS_NONE();
881 :
882 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
883 3 : RETURN_BOOL(pango_layout_get_justify_last_line(layout_object->layout));
884 : }
885 : /* }}} */
886 : #endif
887 :
888 : #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 50, 0)
889 : /* {{{ Sets whether the last line should be stretched to fill the entire width of the layout. */
890 5 : PHP_METHOD(Pango_Layout, setJustifyLastLine)
891 : {
892 : pango_layout_object *layout_object;
893 : bool justify_last_line;
894 :
895 5 : ZEND_PARSE_PARAMETERS_START(1, 1);
896 6 : Z_PARAM_BOOL(justify_last_line)
897 5 : ZEND_PARSE_PARAMETERS_END();
898 :
899 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
900 2 : pango_layout_set_justify_last_line(layout_object->layout, justify_last_line);
901 : }
902 : /* }}} */
903 : #endif
904 :
905 : #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 44, 0)
906 : /* {{{ */
907 3 : PHP_METHOD(Pango_Layout, getLineSpacing)
908 : {
909 : pango_layout_object *layout_object;
910 :
911 3 : ZEND_PARSE_PARAMETERS_NONE();
912 :
913 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
914 2 : RETURN_DOUBLE(pango_layout_get_line_spacing(layout_object->layout));
915 : }
916 : /* }}} */
917 : #endif
918 :
919 : #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 50, 0)
920 : /* {{{ */
921 4 : PHP_METHOD(Pango_Layout, setLineSpacing)
922 : {
923 : pango_layout_object *layout_object;
924 : double factor;
925 :
926 4 : ZEND_PARSE_PARAMETERS_START(1, 1);
927 4 : Z_PARAM_DOUBLE(factor)
928 4 : ZEND_PARSE_PARAMETERS_END();
929 :
930 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
931 1 : pango_layout_set_line_spacing(layout_object->layout, factor);
932 : }
933 : /* }}} */
934 : #endif
935 :
936 : /* {{{ */
937 2 : PHP_METHOD(Pango_Layout, getUnknownGlyphsCount)
938 : {
939 : pango_layout_object *layout_object;
940 :
941 2 : ZEND_PARSE_PARAMETERS_NONE();
942 :
943 2 : layout_object = Z_PANGO_LAYOUT_P(getThis());
944 1 : RETURN_LONG(pango_layout_get_unknown_glyphs_count(layout_object->layout));
945 : }
946 : /* }}} */
947 :
948 : /* {{{ Obtains whether layout is in single paragraph mode. */
949 4 : PHP_METHOD(Pango_Layout, getSingleParagraphMode)
950 : {
951 : pango_layout_object *layout_object;
952 :
953 4 : ZEND_PARSE_PARAMETERS_NONE();
954 :
955 6 : layout_object = Z_PANGO_LAYOUT_P(getThis());
956 3 : RETURN_BOOL(pango_layout_get_single_paragraph_mode(layout_object->layout));
957 : }
958 : /* }}} */
959 :
960 :
961 : /* {{{ Sets the single paragraph mode. */
962 5 : PHP_METHOD(Pango_Layout, setSingleParagraphMode)
963 : {
964 : pango_layout_object *layout_object;
965 : bool setting;
966 :
967 5 : ZEND_PARSE_PARAMETERS_START(1, 1);
968 6 : Z_PARAM_BOOL(setting)
969 5 : ZEND_PARSE_PARAMETERS_END();
970 :
971 4 : layout_object = Z_PANGO_LAYOUT_P(getThis());
972 2 : pango_layout_set_single_paragraph_mode(layout_object->layout, setting);
973 : }
974 : /* }}} */
975 :
976 :
977 : /* ----------------------------------------------------------------
978 : \Pango\Layout Object management
979 : ------------------------------------------------------------------*/
980 :
981 : /* {{{ */
982 60 : static void pango_layout_free_obj(zend_object *zobj)
983 : {
984 60 : pango_layout_object *intern = pango_layout_fetch_object(zobj);
985 :
986 60 : if (!intern) {
987 0 : return;
988 : }
989 :
990 60 : if (intern->layout) {
991 57 : g_object_unref(intern->layout);
992 : }
993 :
994 60 : zval_ptr_dtor(&intern->pango_context_zv);
995 60 : zval_ptr_dtor(&intern->cairo_context_zv);
996 :
997 60 : zend_object_std_dtor(&intern->std);
998 : }
999 : /* }}} */
1000 :
1001 : /* {{{ */
1002 60 : static zend_object* pango_layout_obj_ctor(zend_class_entry *ce, pango_layout_object **intern)
1003 : {
1004 60 : pango_layout_object *object = ecalloc(1, sizeof(pango_layout_object) + zend_object_properties_size(ce));
1005 :
1006 60 : ZVAL_UNDEF(&object->cairo_context_zv);
1007 60 : ZVAL_UNDEF(&object->pango_context_zv);
1008 :
1009 60 : zend_object_std_init(&object->std, ce);
1010 :
1011 60 : object->std.handlers = &pango_layout_object_handlers;
1012 60 : *intern = object;
1013 :
1014 60 : return &object->std;
1015 : }
1016 : /* }}} */
1017 :
1018 : /* {{{ */
1019 60 : static zend_object* pango_layout_create_object(zend_class_entry *ce)
1020 : {
1021 60 : pango_layout_object *intern = NULL;
1022 60 : zend_object *return_value = pango_layout_obj_ctor(ce, &intern);
1023 :
1024 60 : object_properties_init(&intern->std, ce);
1025 60 : return return_value;
1026 : }
1027 : /* }}} */
1028 :
1029 : /* {{{ PHP_MINIT_FUNCTION */
1030 194 : PHP_MINIT_FUNCTION(pango_layout)
1031 : {
1032 194 : memcpy(
1033 : &pango_layout_object_handlers,
1034 : zend_get_std_object_handlers(),
1035 : sizeof(zend_object_handlers)
1036 : );
1037 :
1038 194 : pango_layout_object_handlers.offset = XtOffsetOf(pango_layout_object, std);
1039 194 : pango_layout_object_handlers.free_obj = pango_layout_free_obj;
1040 :
1041 194 : pango_ce_pango_layout = register_class_Pango_Layout();
1042 194 : pango_ce_pango_layout->create_object = pango_layout_create_object;
1043 :
1044 194 : pango_ce_pango_alignment = register_class_Pango_Alignment();
1045 194 : pango_ce_pango_wrap_mode = register_class_Pango_WrapMode();
1046 194 : pango_ce_pango_ellipsize_mode = register_class_Pango_EllipsizeMode();
1047 :
1048 194 : return SUCCESS;
1049 : }
1050 : /* }}} */
|