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 "surface_arginfo.h"
26 :
27 : zend_class_entry *ce_cairo_surface;
28 : zend_class_entry *ce_cairo_content;
29 : zend_class_entry *ce_cairo_surfacetype;
30 :
31 :
32 : static zend_object_handlers cairo_surface_object_handlers;
33 :
34 608 : cairo_surface_object *cairo_surface_fetch_object(zend_object *object)
35 : {
36 608 : return (cairo_surface_object *) ((char*)(object) - XtOffsetOf(cairo_surface_object, std));
37 : }
38 :
39 186 : cairo_surface_object *cairo_surface_object_get(zval *zv)
40 : {
41 186 : cairo_surface_object *object = Z_CAIRO_SURFACE_P(zv);
42 :
43 186 : if (object->surface == NULL) {
44 2 : zend_throw_exception_ex(ce_cairo_exception, 0,
45 : "Internal surface object missing in %s, you must call parent::__construct in extended classes.",
46 2 : ZSTR_VAL(Z_OBJCE_P(zv)->name));
47 2 : return NULL;
48 : }
49 :
50 184 : return object;
51 : }
52 :
53 : /* ----------------------------------------------------------------
54 : Cairo\Pattern Class API
55 : ------------------------------------------------------------------ */
56 :
57 : /* {{{ proto void contruct()
58 : CairoSurface CANNOT be extended in userspace, this will throw an exception on use */
59 1 : PHP_METHOD(Cairo_Surface, __construct) {
60 1 : ZEND_PARSE_PARAMETERS_NONE();
61 1 : zend_throw_exception(ce_cairo_exception, "Cairo\\Surface cannot be constructed", 0);
62 : }
63 : /* }}} */
64 :
65 : /* {{{ proto CairoSurface object \Cairo\Surface::createSimilar(\Cairo\Content content, double width, double height)
66 : Create a new surface that is as compatible as possible with an existing surface. */
67 8 : PHP_METHOD(Cairo_Surface, createSimilar)
68 : {
69 : cairo_surface_object *surface_object, *new_surface_object;
70 : cairo_surface_t *new_surface;
71 : zval *content;
72 : double width, height;
73 :
74 8 : ZEND_PARSE_PARAMETERS_START(3, 3)
75 8 : Z_PARAM_OBJECT_OF_CLASS(content, ce_cairo_content)
76 6 : Z_PARAM_DOUBLE(width)
77 4 : Z_PARAM_DOUBLE(height)
78 8 : ZEND_PARSE_PARAMETERS_END();
79 :
80 2 : surface_object = cairo_surface_object_get(getThis());
81 1 : if (!surface_object) {
82 0 : RETURN_THROWS();
83 : }
84 :
85 2 : new_surface = cairo_surface_create_similar(
86 : surface_object->surface,
87 2 : Z_LVAL_P(zend_enum_fetch_case_value(Z_OBJ_P(content))),
88 : width,
89 : height
90 : );
91 :
92 : /* we can't always rely on the same type of surface being returned, so we use php_cairo_get_surface_ce */
93 1 : object_init_ex(return_value, php_cairo_get_surface_ce(new_surface));
94 1 : new_surface_object = Z_CAIRO_SURFACE_P(return_value);
95 1 : if (!new_surface_object) {
96 0 : RETURN_NULL();
97 : }
98 :
99 1 : new_surface_object->surface = new_surface;
100 : }
101 : /* }}} */
102 :
103 : /* {{{ proto CairoSurface object \Cairo\Surface::createSimilarImage(\Cairo\Format format, double width, double height)
104 : Create a new image surface that is as compatible as possible for uploading to and the use in conjunction with an existing surface.
105 : Unlike cairo_surface_create_similar() the new image surface won't inherit the device scale from other. */
106 8 : PHP_METHOD(Cairo_Surface, createSimilarImage)
107 : {
108 : cairo_surface_object *surface_object, *new_surface_object;
109 : cairo_surface_t *new_surface;
110 : double width, height;
111 : zval *format;
112 :
113 8 : ZEND_PARSE_PARAMETERS_START(3, 3)
114 8 : Z_PARAM_OBJECT_OF_CLASS(format, ce_cairo_format)
115 6 : Z_PARAM_DOUBLE(width)
116 4 : Z_PARAM_DOUBLE(height)
117 8 : ZEND_PARSE_PARAMETERS_END();
118 :
119 2 : surface_object = cairo_surface_object_get(getThis());
120 1 : if (!surface_object) {
121 0 : RETURN_THROWS();
122 : }
123 :
124 2 : new_surface = cairo_surface_create_similar_image(
125 : surface_object->surface,
126 2 : Z_LVAL_P(zend_enum_fetch_case_value(Z_OBJ_P(format))),
127 : width,
128 : height
129 : );
130 :
131 : /* --> because of used method php_cairo_get_surface_ce() should always give 'ce_cairo_imagesurface' */
132 1 : object_init_ex(return_value, php_cairo_get_surface_ce(new_surface));
133 1 : new_surface_object = Z_CAIRO_SURFACE_P(return_value);
134 1 : if (!new_surface_object) {
135 0 : RETURN_NULL();
136 : }
137 :
138 1 : new_surface_object->surface = new_surface;
139 : }
140 : /* }}} */
141 :
142 : /* {{{ proto CairoSurface object \Cairo\Surface::createForRectangle(double x, double y, double width, double height)
143 : create a new surface that is a rectangle within the target surface. */
144 10 : PHP_METHOD(Cairo_Surface, createForRectangle)
145 : {
146 10 : zval *surface_zval = NULL;
147 : cairo_surface_object *surface_object, *new_surface_object;
148 : cairo_surface_t *new_surface;
149 : double x, y, width, height;
150 :
151 10 : ZEND_PARSE_PARAMETERS_START(4, 4)
152 10 : Z_PARAM_DOUBLE(x)
153 8 : Z_PARAM_DOUBLE(y)
154 6 : Z_PARAM_DOUBLE(width)
155 4 : Z_PARAM_DOUBLE(height)
156 10 : ZEND_PARSE_PARAMETERS_END();
157 :
158 2 : surface_zval = getThis();
159 1 : surface_object = cairo_surface_object_get(surface_zval);
160 1 : if (!surface_object) {
161 0 : RETURN_THROWS();
162 : }
163 :
164 1 : new_surface = cairo_surface_create_for_rectangle(surface_object->surface, x, y, width, height);
165 :
166 1 : object_init_ex(return_value, php_cairo_get_subsurface_ce());
167 1 : new_surface_object = Z_CAIRO_SURFACE_P(return_value);
168 : // Store reference to the parent object
169 1 : ZVAL_COPY(&new_surface_object->parent_zval, surface_zval);
170 1 : new_surface_object->surface = new_surface;
171 : }
172 : /* }}} */
173 :
174 :
175 : /* {{{ proto \Cairo\Status \Cairo\Surface::getStatus()
176 : Checks whether an error has previously occurred for this surface. */
177 2 : PHP_METHOD(Cairo_Surface, getStatus)
178 : {
179 : cairo_surface_object *surface_object;
180 : zval status_case;
181 :
182 3 : ZEND_PARSE_PARAMETERS_NONE();
183 :
184 2 : surface_object = cairo_surface_object_get(getThis());
185 1 : if (!surface_object) {
186 0 : RETURN_THROWS();
187 : }
188 :
189 1 : status_case = php_enum_from_cairo_c_enum(
190 : ce_cairo_status,
191 1 : cairo_surface_status(surface_object->surface)
192 : );
193 :
194 1 : if (Z_TYPE(status_case) == IS_OBJECT) {
195 2 : RETURN_ZVAL(&status_case, 1, 1);
196 : }
197 : }
198 : /* }}} */
199 :
200 : /* {{{ proto void \Cairo\Surface::finish()
201 : This function finishes the surface and drops all references to external resources. For example,
202 : for the Xlib backend it means that cairo will no longer access the drawable, which can be freed. */
203 4 : PHP_METHOD(Cairo_Surface, finish)
204 : {
205 : cairo_surface_object *surface_object;
206 :
207 4 : ZEND_PARSE_PARAMETERS_NONE();
208 :
209 6 : surface_object = cairo_surface_object_get(getThis());
210 3 : if (!surface_object) {
211 2 : RETURN_THROWS();
212 : }
213 :
214 1 : cairo_surface_finish(surface_object->surface);
215 : }
216 : /* }}} */
217 :
218 : /* {{{ proto void \Cairo\Surface::flush()
219 : Do any pending drawing for the surface and also restore any temporary modification's cairo has made
220 : to the surface's state. This function must be called before switching from drawing on the surface
221 : with cairo to drawing on it directly with native APIs. */
222 2 : PHP_METHOD(Cairo_Surface, flush)
223 : {
224 : cairo_surface_object *surface_object;
225 :
226 2 : ZEND_PARSE_PARAMETERS_NONE();
227 :
228 2 : surface_object = cairo_surface_object_get(getThis());
229 1 : if (!surface_object) {
230 0 : RETURN_THROWS();
231 : }
232 :
233 1 : cairo_surface_flush(surface_object->surface);
234 : }
235 : /* }}} */
236 :
237 : /* {{{ proto CairoFontOptions object \Cairo\Surface::getFontOptions()
238 : Retrieves the default font rendering options for the surface. */
239 2 : PHP_METHOD(Cairo_Surface, getFontOptions)
240 : {
241 : cairo_surface_object *surface_object;
242 : cairo_font_options_object *font_object;
243 2 : cairo_font_options_t *options = cairo_font_options_create();
244 :
245 2 : ZEND_PARSE_PARAMETERS_NONE();
246 :
247 2 : surface_object = cairo_surface_object_get(getThis());
248 1 : if (!surface_object) {
249 0 : RETURN_THROWS();
250 : }
251 :
252 1 : object_init_ex(return_value, php_cairo_get_fontoptions_ce());
253 1 : font_object = Z_CAIRO_FONT_OPTIONS_P(return_value);
254 :
255 1 : cairo_surface_get_font_options(surface_object->surface, options);
256 1 : font_object->font_options = options;
257 : }
258 : /* }}} */
259 :
260 : /* {{{ proto \Cairo\Content \Cairo\Surface::getContent()
261 : This function returns the content type of surface which indicates whether the surface contains color and/or alpha information. */
262 2 : PHP_METHOD(Cairo_Surface, getContent)
263 : {
264 : cairo_surface_object *surface_object;
265 : zval content_case;
266 :
267 3 : ZEND_PARSE_PARAMETERS_NONE();
268 :
269 2 : surface_object = cairo_surface_object_get(getThis());
270 1 : if (!surface_object) {
271 0 : RETURN_THROWS();
272 : }
273 :
274 1 : content_case = php_enum_from_cairo_c_enum(
275 : ce_cairo_content,
276 1 : cairo_surface_get_content(surface_object->surface)
277 : );
278 :
279 1 : if (Z_TYPE(content_case) == IS_OBJECT) {
280 2 : RETURN_ZVAL(&content_case, 1, 1);
281 : }
282 : }
283 : /* }}} */
284 :
285 : /* {{{ proto void \Cairo\Surface::markDirty()
286 : Tells cairo that drawing has been done to surface using means other than cairo, and that cairo should reread any cached areas. */
287 2 : PHP_METHOD(Cairo_Surface, markDirty)
288 : {
289 : cairo_surface_object *surface_object;
290 :
291 2 : ZEND_PARSE_PARAMETERS_NONE();
292 :
293 2 : surface_object = cairo_surface_object_get(getThis());
294 1 : if (!surface_object) {
295 0 : RETURN_THROWS();
296 : }
297 :
298 1 : cairo_surface_mark_dirty(surface_object->surface);
299 : }
300 : /* }}} */
301 :
302 : /* {{{ proto void \Cairo\Surface::markDirtyRectangle(float x, float y, float width, float height)
303 : Drawing has been done only to the specified rectangle, so that cairo can retain cached contents for other parts of the surface.
304 : Any cached clip set on the surface will be reset by this function, to make sure that future cairo calls have the clip set that they expect.*/
305 10 : PHP_METHOD(Cairo_Surface, markDirtyRectangle)
306 : {
307 : cairo_surface_object *surface_object;
308 10 : long x = 0, y = 0, width = 0, height = 0;
309 :
310 10 : ZEND_PARSE_PARAMETERS_START(4, 4)
311 10 : Z_PARAM_LONG(x)
312 8 : Z_PARAM_LONG(y)
313 6 : Z_PARAM_LONG(width)
314 4 : Z_PARAM_LONG(height)
315 10 : ZEND_PARSE_PARAMETERS_END();
316 :
317 2 : surface_object = cairo_surface_object_get(getThis());
318 1 : if (!surface_object) {
319 0 : RETURN_THROWS();
320 : }
321 :
322 1 : cairo_surface_mark_dirty_rectangle(surface_object->surface, x, y, width, height);
323 : }
324 : /* }}} */
325 :
326 : /* {{{ proto void \Cairo\Surface::setDeviceOffset(float x, float y)
327 : Sets an offset that is added to the device coordinates determined by the CTM when drawing to surface. */
328 6 : PHP_METHOD(Cairo_Surface, setDeviceOffset)
329 : {
330 : cairo_surface_object *surface_object;
331 6 : double x = 0.0, y = 0.0;
332 :
333 6 : ZEND_PARSE_PARAMETERS_START(2, 2)
334 6 : Z_PARAM_DOUBLE(x)
335 4 : Z_PARAM_DOUBLE(y)
336 6 : ZEND_PARSE_PARAMETERS_END();
337 :
338 2 : surface_object = cairo_surface_object_get(getThis());
339 1 : if (!surface_object) {
340 0 : RETURN_THROWS();
341 : }
342 :
343 1 : cairo_surface_set_device_offset(surface_object->surface, x, y);
344 : }
345 : /* }}} */
346 :
347 : /* {{{ proto array \Cairo\Surface::getDeviceOffset()
348 : This function returns the previous device offset */
349 2 : PHP_METHOD(Cairo_Surface, getDeviceOffset)
350 : {
351 : cairo_surface_object *surface_object;
352 : double x, y;
353 :
354 2 : ZEND_PARSE_PARAMETERS_NONE();
355 :
356 2 : surface_object = cairo_surface_object_get(getThis());
357 1 : if (!surface_object) {
358 0 : RETURN_THROWS();
359 : }
360 :
361 1 : cairo_surface_get_device_offset(surface_object->surface, &x, &y);
362 :
363 1 : array_init(return_value);
364 1 : add_assoc_double(return_value, "x", x);
365 1 : add_assoc_double(return_value, "y", y);
366 : }
367 : /* }}} */
368 :
369 : /* {{{ proto void \Cairo\Surface::setDeviceScale(float x, float y)
370 : Sets a scale that is multiplied to the device coordinates determined by the CTM when drawing to surface.
371 : One common use for this is to render to very high resolution display devices at a scale factor,
372 : so that code that assumes 1 pixel will be a certain size will still work.
373 : Setting a transformation via cairo_translate() isn't sufficient to do this,
374 : since functions like cairo_device_to_user() will expose the hidden scale. */
375 7 : PHP_METHOD(Cairo_Surface, setDeviceScale)
376 : {
377 : cairo_surface_object *surface_object;
378 7 : double x = 0.0, y = 0.0;
379 :
380 7 : ZEND_PARSE_PARAMETERS_START(2, 2)
381 8 : Z_PARAM_DOUBLE(x)
382 6 : Z_PARAM_DOUBLE(y)
383 7 : ZEND_PARSE_PARAMETERS_END();
384 :
385 4 : surface_object = cairo_surface_object_get(getThis());
386 2 : if (!surface_object) {
387 0 : RETURN_THROWS();
388 : }
389 :
390 2 : cairo_surface_set_device_scale(surface_object->surface, x, y);
391 : }
392 : /* }}} */
393 :
394 : /* {{{ proto array \Cairo\Surface::getDeviceScale()
395 : This function returns the previous set device scale. */
396 3 : PHP_METHOD(Cairo_Surface, getDeviceScale)
397 : {
398 : cairo_surface_object *surface_object;
399 : double x, y;
400 :
401 3 : ZEND_PARSE_PARAMETERS_NONE();
402 :
403 4 : surface_object = cairo_surface_object_get(getThis());
404 2 : if (!surface_object) {
405 0 : RETURN_THROWS();
406 : }
407 :
408 2 : cairo_surface_get_device_scale(surface_object->surface, &x, &y);
409 :
410 2 : array_init(return_value);
411 2 : add_assoc_double(return_value, "x", x);
412 2 : add_assoc_double(return_value, "y", y);
413 : }
414 : /* }}} */
415 :
416 : /* {{{ proto void \Cairo\Surface::setFallbackResolution(float x, float y)
417 : Set the horizontal and vertical resolution for image fallbacks.
418 : When certain operations aren't supported natively by a backend, cairo will fallback by
419 : rendering operations to an image and then overlaying that image onto the output. */
420 6 : PHP_METHOD(Cairo_Surface, setFallbackResolution)
421 : {
422 : cairo_surface_object *surface_object;
423 6 : double x = 0.0, y = 0.0;
424 :
425 6 : ZEND_PARSE_PARAMETERS_START(2, 2)
426 6 : Z_PARAM_DOUBLE(x)
427 4 : Z_PARAM_DOUBLE(y)
428 6 : ZEND_PARSE_PARAMETERS_END();
429 :
430 2 : surface_object = cairo_surface_object_get(getThis());
431 1 : if (!surface_object) {
432 0 : RETURN_THROWS();
433 : }
434 :
435 1 : cairo_surface_set_fallback_resolution(surface_object->surface, x, y);
436 : }
437 : /* }}} */
438 :
439 : /* {{{ proto array \Cairo\Surface::getFallbackResolution()
440 : This function returns the previous fallback resolution */
441 2 : PHP_METHOD(Cairo_Surface, getFallbackResolution)
442 : {
443 : cairo_surface_object *surface_object;
444 : double x, y;
445 :
446 2 : ZEND_PARSE_PARAMETERS_NONE();
447 :
448 2 : surface_object = cairo_surface_object_get(getThis());
449 1 : if (!surface_object) {
450 0 : RETURN_THROWS();
451 : }
452 :
453 1 : cairo_surface_get_fallback_resolution(surface_object->surface, &x, &y);
454 :
455 1 : array_init(return_value);
456 1 : add_assoc_double(return_value, "x", x);
457 1 : add_assoc_double(return_value, "y", y);
458 : }
459 : /* }}} */
460 :
461 : /* {{{ proto \Cairo\Surface\Type \Cairo\Surface::getType()
462 : This function returns the type of the backend used to create a surface. */
463 2 : PHP_METHOD(Cairo_Surface, getType)
464 : {
465 : cairo_surface_object *surface_object;
466 : zval surface_case;
467 :
468 3 : ZEND_PARSE_PARAMETERS_NONE();
469 :
470 2 : surface_object = cairo_surface_object_get(getThis());
471 1 : if (!surface_object) {
472 0 : RETURN_THROWS();
473 : }
474 :
475 1 : surface_case = php_enum_from_cairo_c_enum(
476 : ce_cairo_surfacetype,
477 1 : cairo_surface_get_type(surface_object->surface)
478 : );
479 :
480 1 : if (Z_TYPE(surface_case) == IS_OBJECT) {
481 2 : RETURN_ZVAL(&surface_case, 1, 1);
482 : }
483 : }
484 : /* }}} */
485 :
486 : /* {{{ proto void \Cairo\Surface::showPage()
487 : Emits and clears the current page for backends that support multiple pages.
488 : Same as CairoContext->showPage(); */
489 2 : PHP_METHOD(Cairo_Surface, showPage)
490 : {
491 : cairo_surface_object *surface_object;
492 :
493 2 : ZEND_PARSE_PARAMETERS_NONE();
494 :
495 2 : surface_object = cairo_surface_object_get(getThis());
496 1 : if (!surface_object) {
497 0 : RETURN_THROWS();
498 : }
499 :
500 1 : cairo_surface_show_page(surface_object->surface);
501 : }
502 : /* }}} */
503 :
504 : /* {{{ proto void \Cairo\Surface::copyPage()
505 : Emits the current page for backends that support multiple pages,
506 : but doesn't clear it, so that the contents of the current page will be retained for the next page.
507 : Same as CairoContext->copyPage(); */
508 2 : PHP_METHOD(Cairo_Surface, copyPage)
509 : {
510 : cairo_surface_object *surface_object;
511 :
512 2 : ZEND_PARSE_PARAMETERS_NONE();
513 :
514 2 : surface_object = cairo_surface_object_get(getThis());
515 1 : if (!surface_object) {
516 0 : RETURN_THROWS();
517 : }
518 :
519 1 : cairo_surface_copy_page(surface_object->surface);
520 : }
521 : /* }}} */
522 :
523 : /* {{{ proto bool \Cairo\Surface::hasShowTextGlyphs()
524 : Returns whether the surface supports sophisticated cairo_show_text_glyphs() operations
525 : Users can use this function to avoid computing UTF-8 text and cluster mapping if the target surface does not use it. */
526 2 : PHP_METHOD(Cairo_Surface, hasShowTextGlyphs)
527 : {
528 : cairo_surface_object *surface_object;
529 :
530 2 : ZEND_PARSE_PARAMETERS_NONE();
531 :
532 2 : surface_object = cairo_surface_object_get(getThis());
533 1 : if (!surface_object) {
534 0 : RETURN_THROWS();
535 : }
536 :
537 1 : RETURN_BOOL(cairo_surface_has_show_text_glyphs(surface_object->surface));
538 : }
539 : /* }}} */
540 :
541 : /* {{{ proto CairoSurface object \Cairo\Surface::mapToImage([\Cairo\Rectangle rectangle])
542 : .... */
543 6 : PHP_METHOD(Cairo_Surface, mapToImage)
544 : {
545 : cairo_surface_object *surface_object, *new_surface_object;
546 : cairo_surface_t *new_surface;
547 6 : zval *rectangle_zval = NULL;
548 : cairo_rectangle_object *rectangle_object;
549 : cairo_rectangle_int_t int_rect;
550 :
551 6 : ZEND_PARSE_PARAMETERS_START(0, 1)
552 5 : Z_PARAM_OPTIONAL
553 9 : Z_PARAM_OBJECT_OF_CLASS(rectangle_zval, ce_cairo_rectangle)
554 6 : ZEND_PARSE_PARAMETERS_END();
555 :
556 8 : surface_object = cairo_surface_object_get(getThis());
557 4 : if (!surface_object) {
558 0 : RETURN_THROWS();
559 : }
560 :
561 7 : if (rectangle_zval != NULL && Z_TYPE_P(rectangle_zval) == IS_OBJECT) {
562 3 : rectangle_object = Z_CAIRO_RECTANGLE_P(rectangle_zval);
563 3 : int_rect = cairo_expand_to_rectangle_int(rectangle_object->rect);
564 3 : new_surface = cairo_surface_map_to_image(surface_object->surface, &int_rect);
565 3 : cairo_surface_reference(new_surface);
566 : } else {
567 1 : new_surface = cairo_surface_map_to_image(surface_object->surface, NULL);
568 : }
569 :
570 4 : object_init_ex(return_value, php_cairo_get_imagesurface_ce());
571 4 : new_surface_object = Z_CAIRO_SURFACE_P(return_value);
572 4 : if (!new_surface_object) {
573 0 : RETURN_NULL();
574 : }
575 :
576 4 : new_surface_object->surface = new_surface;
577 4 : if (php_cairo_throw_exception(cairo_surface_status(surface_object->surface))) {
578 0 : RETURN_THROWS();
579 : }
580 : }
581 : /* }}} */
582 :
583 : /* {{{ proto CairoSurface object \Cairo\Surface::unmapImage([\Cairo\Sourface\Image image_surface])
584 : .... */
585 4 : PHP_METHOD(Cairo_Surface, unmapImage)
586 : {
587 : cairo_surface_object *surface_object, *image_surface_object;
588 : zval *image_surface_zval;
589 :
590 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
591 4 : Z_PARAM_OBJECT_OF_CLASS(image_surface_zval, ce_cairo_imagesurface)
592 4 : ZEND_PARSE_PARAMETERS_END();
593 :
594 2 : surface_object = cairo_surface_object_get(getThis());
595 1 : if (!surface_object) {
596 0 : RETURN_THROWS();
597 : }
598 :
599 1 : image_surface_object = cairo_surface_object_get(image_surface_zval);
600 1 : if (!image_surface_object) {
601 0 : RETURN_THROWS();
602 : }
603 :
604 1 : cairo_surface_unmap_image(surface_object->surface, image_surface_object->surface);
605 :
606 1 : if (php_cairo_throw_exception(cairo_surface_status(surface_object->surface))) {
607 0 : RETURN_THROWS();
608 : }
609 : }
610 : /* }}} */
611 :
612 :
613 : #ifdef CAIRO_HAS_PNG_FUNCTIONS
614 : /* {{{ proto void \Cairo\Surface::writeToPng(file|resource file)
615 : Writes the contents of surface to a new file filename or PHP stream as a PNG image.
616 : Unlike some other stream supporting functions, you may NOT pass a null filename */
617 6 : PHP_METHOD(Cairo_Surface, writeToPng)
618 : {
619 : cairo_surface_object *surface_object;
620 6 : zval *stream_zval = NULL;
621 : stream_closure *closure;
622 6 : php_stream *stream = NULL;
623 6 : bool owned_stream = false;
624 : cairo_status_t status;
625 :
626 6 : ZEND_PARSE_PARAMETERS_START(1, 1)
627 4 : Z_PARAM_ZVAL(stream_zval)
628 8 : ZEND_PARSE_PARAMETERS_END();
629 :
630 8 : surface_object = cairo_surface_object_get(getThis());
631 4 : if (!surface_object) {
632 0 : RETURN_THROWS();
633 : }
634 :
635 8 : if (Z_TYPE_P(stream_zval) == IS_STRING && Z_STRLEN_P(stream_zval) > 0) {
636 1 : stream = php_stream_open_wrapper(Z_STRVAL_P(stream_zval), "w+b", REPORT_ERRORS, NULL);
637 1 : owned_stream = 1;
638 6 : } else if (Z_TYPE_P(stream_zval) == IS_RESOURCE) {
639 1 : php_stream_from_zval(stream, stream_zval);
640 : } else {
641 2 : zend_throw_exception(ce_cairo_exception, "Cairo\\Surface::writeToPng() expects parameter 1 to be a (not empty) string or a stream resource", 0);
642 2 : RETURN_THROWS();
643 : }
644 :
645 : /* Pack stream into struct */
646 2 : closure = ecalloc(1, sizeof(stream_closure));
647 2 : closure->stream = stream;
648 2 : closure->owned_stream = owned_stream;
649 :
650 2 : status = cairo_surface_write_to_png_stream(surface_object->surface, php_cairo_write_func, (void *)closure);
651 2 : if (owned_stream) {
652 1 : php_stream_close(stream);
653 : }
654 2 : efree(closure);
655 :
656 2 : if (php_cairo_throw_exception(status)) {
657 0 : RETURN_THROWS();
658 : }
659 : }
660 : /* }}} */
661 : #endif
662 :
663 :
664 : #ifdef CAIRO_HAS_JPEG_FUNCTIONS
665 : /* {{{ proto void \Cairo\Surface::writeToJpeg(file|resource file)
666 : Writes the contents of surface to a new file filename or PHP stream as a JPEG image.
667 : Unlike some other stream supporting functions, you may NOT pass a null filename */
668 6 : PHP_METHOD(Cairo_Surface, writeToJpeg)
669 : {
670 : cairo_surface_object *surface_object;
671 6 : zval *stream_zval = NULL;
672 : stream_closure *closure;
673 6 : php_stream *stream = NULL;
674 6 : bool owned_stream = false;
675 : cairo_status_t status;
676 6 : double quality = 90;
677 :
678 6 : ZEND_PARSE_PARAMETERS_START(1, 2)
679 4 : Z_PARAM_ZVAL(stream_zval)
680 4 : Z_PARAM_OPTIONAL
681 4 : Z_PARAM_DOUBLE(quality)
682 6 : ZEND_PARSE_PARAMETERS_END();
683 :
684 8 : surface_object = cairo_surface_object_get(getThis());
685 4 : if (!surface_object) {
686 0 : RETURN_THROWS();
687 : }
688 :
689 8 : if (Z_TYPE_P(stream_zval) == IS_STRING && Z_STRLEN_P(stream_zval) > 0) {
690 1 : stream = php_stream_open_wrapper(Z_STRVAL_P(stream_zval), "w+b", REPORT_ERRORS, NULL);
691 1 : owned_stream = 1;
692 6 : } else if (Z_TYPE_P(stream_zval) == IS_RESOURCE) {
693 1 : php_stream_from_zval(stream, stream_zval);
694 : } else {
695 2 : zend_throw_exception(ce_cairo_exception, "Cairo\\Surface::writeToJpeg() expects parameter 1 to be a (not empty) string or a stream resource", 0);
696 2 : RETURN_THROWS();
697 : }
698 :
699 : /* Pack stream into struct */
700 2 : closure = ecalloc(1, sizeof(stream_closure));
701 2 : closure->stream = stream;
702 2 : closure->owned_stream = owned_stream;
703 :
704 2 : status = cairo_image_surface_write_to_jpeg_stream(
705 : surface_object->surface,
706 : php_cairo_write_func,
707 : (void *)closure,
708 : quality
709 : );
710 2 : if (owned_stream) {
711 1 : php_stream_close(stream);
712 : }
713 2 : efree(closure);
714 :
715 2 : if (php_cairo_throw_exception(status)) {
716 0 : RETURN_THROWS();
717 : }
718 : }
719 : /* }}} */
720 : #endif
721 :
722 :
723 : /* ----------------------------------------------------------------
724 : Cairo\Surface Object management
725 : ------------------------------------------------------------------*/
726 :
727 : /* {{{ */
728 227 : static void cairo_surface_free_obj(zend_object *object)
729 : {
730 227 : cairo_surface_object *intern = cairo_surface_fetch_object(object);
731 :
732 227 : if (!intern) {
733 0 : return;
734 : }
735 :
736 : /* buffer for the create_from_data image stuff */
737 227 : if (intern->buffer) {
738 1 : efree(intern->buffer);
739 1 : intern->buffer = NULL;
740 : }
741 :
742 227 : if (intern->surface) {
743 189 : cairo_surface_finish(intern->surface);
744 189 : cairo_surface_destroy(intern->surface);
745 189 : intern->surface = NULL;
746 : }
747 :
748 : /* closure free up time */
749 227 : if (intern->closure) {
750 8 : if (intern->closure->owned_stream == 1) {
751 3 : php_stream_close(intern->closure->stream);
752 : }
753 8 : efree(intern->closure);
754 8 : intern->closure = NULL;
755 : }
756 :
757 227 : zval_ptr_dtor(&intern->parent_zval);
758 :
759 227 : zend_object_std_dtor(&intern->std);
760 : }
761 : /* }}} */
762 :
763 : /* {{{ */
764 227 : static zend_object* cairo_surface_obj_ctor(zend_class_entry *ce, cairo_surface_object **intern)
765 : {
766 227 : cairo_surface_object *object = ecalloc(1, sizeof(cairo_surface_object) + zend_object_properties_size(ce));
767 :
768 227 : object->surface = NULL;
769 227 : object->buffer = NULL;
770 227 : object->closure = NULL;
771 227 : ZVAL_UNDEF(&object->parent_zval);
772 :
773 227 : zend_object_std_init(&object->std, ce);
774 227 : object->std.handlers = &cairo_surface_object_handlers;
775 227 : *intern = object;
776 :
777 227 : return &object->std;
778 : }
779 : /* }}} */
780 :
781 : /* {{{ */
782 227 : zend_object* cairo_surface_create_object(zend_class_entry *ce)
783 : {
784 227 : cairo_surface_object *surface = NULL;
785 227 : zend_object *return_value = cairo_surface_obj_ctor(ce, &surface);
786 :
787 227 : object_properties_init(&surface->std, ce);
788 227 : return return_value;
789 : }
790 : /* }}} */
791 :
792 :
793 : /* ----------------------------------------------------------------
794 : Cairo\Surface C API
795 : ------------------------------------------------------------------*/
796 :
797 : /* Helper methods for stream surface read/writes */
798 260 : cairo_status_t php_cairo_write_func(void *closure, const unsigned char *data, unsigned int length)
799 : {
800 : size_t written;
801 : stream_closure *cast_closure;
802 :
803 260 : cast_closure = (stream_closure *)closure;
804 :
805 260 : written = php_stream_write(cast_closure->stream, data, length);
806 260 : if (written == length) {
807 260 : return CAIRO_STATUS_SUCCESS;
808 : }
809 :
810 0 : return CAIRO_STATUS_WRITE_ERROR;
811 : }
812 :
813 650 : cairo_status_t php_cairo_read_func(void *closure, const unsigned char *data, unsigned int length)
814 : {
815 : unsigned int read;
816 : stream_closure *cast_closure;
817 :
818 650 : cast_closure = (stream_closure *)closure;
819 :
820 650 : read = php_stream_read(cast_closure->stream, (char *)data, length);
821 650 : if (read == length) {
822 649 : return CAIRO_STATUS_SUCCESS;
823 : }
824 :
825 1 : return CAIRO_STATUS_READ_ERROR;
826 : }
827 :
828 3 : zend_class_entry* php_cairo_get_surface_ce(cairo_surface_t *surface)
829 : {
830 : zend_class_entry *type;
831 :
832 3 : if (surface == NULL) {
833 0 : return ce_cairo_surface;
834 : }
835 :
836 3 : switch (cairo_surface_get_type(surface)) {
837 3 : case CAIRO_SURFACE_TYPE_IMAGE:
838 3 : type = ce_cairo_imagesurface;
839 3 : break;
840 :
841 : #ifdef CAIRO_HAS_PDF_SURFACE
842 0 : case CAIRO_SURFACE_TYPE_PDF:
843 0 : type = ce_cairo_pdfsurface;
844 0 : break;
845 : #endif
846 : #ifdef CAIRO_HAS_SVG_SURFACE
847 0 : case CAIRO_SURFACE_TYPE_SVG:
848 0 : type = ce_cairo_svgsurface;
849 0 : break;
850 : #endif
851 :
852 : #ifdef CAIRO_HAS_PS_SURFACE
853 0 : case CAIRO_SURFACE_TYPE_PS:
854 0 : type = ce_cairo_pssurface;
855 0 : break;
856 : #endif
857 :
858 : #ifdef CAIRO_HAS_RECORDING_SURFACE
859 0 : case CAIRO_SURFACE_TYPE_RECORDING:
860 0 : type = ce_cairo_recordingsurface;
861 0 : break;
862 : #endif
863 : /*
864 : #ifdef CAIRO_HAS_WIN32_SURFACE
865 : case CAIRO_SURFACE_TYPE_WIN32:
866 : type = get_CairoWin32Surface_ce_ptr();
867 : break;
868 : #endif
869 : #ifdef CAIRO_HAS_XLIB_SURFACE
870 : case CAIRO_SURFACE_TYPE_XLIB:
871 : type = get_CairoXlibSurface_ce_ptr();
872 : break;
873 : #endif
874 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
875 : case CAIRO_SURFACE_TYPE_QUARTZ:
876 : type = get_CairoQuartzSurface_ce_ptr();
877 : break;
878 : #endif */
879 :
880 0 : case CAIRO_SURFACE_TYPE_SUBSURFACE:
881 0 : type = ce_cairo_subsurface;
882 0 : break;
883 :
884 0 : default:
885 0 : php_error(E_WARNING, "Unsupported Cairo Surface Type");
886 0 : return NULL;
887 : }
888 3 : return type;
889 : }
890 :
891 : /* ----------------------------------------------------------------
892 : Cairo\Surface Definition and registration
893 : ------------------------------------------------------------------*/
894 :
895 : /* {{{ PHP_MINIT_FUNCTION */
896 424 : PHP_MINIT_FUNCTION(cairo_surface)
897 : {
898 424 : memcpy(
899 : &cairo_surface_object_handlers,
900 : zend_get_std_object_handlers(),
901 : sizeof(cairo_surface_object_handlers)
902 : );
903 :
904 : /* Surface */
905 424 : cairo_surface_object_handlers.offset = XtOffsetOf(cairo_surface_object, std);
906 424 : cairo_surface_object_handlers.free_obj = cairo_surface_free_obj;
907 :
908 424 : ce_cairo_surface = register_class_Cairo_Surface();
909 424 : ce_cairo_surface->create_object = cairo_surface_create_object;
910 :
911 : /* CairoContent */
912 424 : ce_cairo_content = register_class_Cairo_Surface_Content();
913 :
914 : /* SurfaceType */
915 424 : ce_cairo_surfacetype = register_class_Cairo_Surface_Type();
916 :
917 424 : return SUCCESS;
918 : }
|