Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-directfb-surface.c
blobaa67b023bb339737c01d4c37b7fa50be1d81ef9e
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2003 University of Southern California
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is University of Southern
31 * California.
33 * Contributor(s):
34 * Michael Emmel <mike.emmel@gmail.com>
35 * Claudio Ciccani <klan@users.sf.net>
38 #include "cairoint.h"
39 #include "cairo-directfb.h"
41 #include <directfb.h>
42 #include <direct/types.h>
43 #include <direct/debug.h>
44 #include <direct/memcpy.h>
45 #include <direct/util.h>
47 #include "cairo-clip-private.h"
50 * Rectangle works fine.
51 * Bugs 361377, 359553, 359243 in Gnome BTS are caused
52 * by GDK/DirectFB, not by Cairo/DirectFB.
54 #define DFB_RECTANGLES 1
57 * Composite works fine.
59 #define DFB_COMPOSITE 1
62 * CompositeTrapezoids works (without antialiasing).
64 #define DFB_COMPOSITE_TRAPEZOIDS 1
67 * ShowGlyphs works fine.
69 #define DFB_SHOW_GLYPHS 1
72 D_DEBUG_DOMAIN (CairoDFB_Acquire, "CairoDFB/Acquire", "Cairo DirectFB Acquire");
73 D_DEBUG_DOMAIN (CairoDFB_Clip, "CairoDFB/Clip", "Cairo DirectFB Clipping");
74 D_DEBUG_DOMAIN (CairoDFB_Font, "CairoDFB/Font", "Cairo DirectFB Font Rendering");
75 D_DEBUG_DOMAIN (CairoDFB_Render, "CairoDFB/Render", "Cairo DirectFB Rendering");
76 D_DEBUG_DOMAIN (CairoDFB_Surface, "CairoDFB/Surface", "Cairo DirectFB Surface");
78 /*****************************************************************************/
80 typedef struct _cairo_directfb_surface {
81 cairo_surface_t base;
82 cairo_format_t format;
83 cairo_content_t content;
85 IDirectFB *dfb;
86 IDirectFBSurface *dfbsurface;
87 IDirectFBSurface *tmpsurface;
89 cairo_bool_t has_clip;
90 DFBRegion *clips;
91 int n_clips;
93 int width;
94 int height;
96 unsigned local : 1;
97 unsigned blit_premultiplied : 1;
98 } cairo_directfb_surface_t;
101 typedef struct _cairo_directfb_font_cache {
102 IDirectFB *dfb;
103 IDirectFBSurface *dfbsurface;
105 int width;
106 int height;
108 /* coordinates within the surface
109 * of the last loaded glyph */
110 int x;
111 int y;
112 } cairo_directfb_font_cache_t;
114 static cairo_surface_backend_t _cairo_directfb_surface_backend;
116 /*****************************************************************************/
118 static int _directfb_argb_font = 0;
120 /*****************************************************************************/
122 #define RUN_CLIPPED(surface, clip, func) {\
123 if ((surface)->has_clip) {\
124 int k;\
125 for (k = 0; k < (surface)->n_clips; k++) {\
126 if (clip) {\
127 DFBRegion reg = (surface)->clips[k];\
128 DFBRegion *cli = (clip);\
129 if (reg.x2 < cli->x1 || reg.y2 < cli->y1 ||\
130 reg.x1 > cli->x2 || reg.y1 > cli->y2)\
131 continue;\
132 if (reg.x1 < cli->x1)\
133 reg.x1 = cli->x1;\
134 if (reg.y1 < cli->y1)\
135 reg.y1 = cli->y1;\
136 if (reg.x2 > cli->x2)\
137 reg.x2 = cli->x2;\
138 if (reg.y2 > cli->y2)\
139 reg.y2 = cli->y2;\
140 (surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg);\
141 } else {\
142 (surface)->dfbsurface->SetClip ((surface)->dfbsurface,\
143 &(surface)->clips[k]);\
145 func;\
147 } else {\
148 (surface)->dfbsurface->SetClip ((surface)->dfbsurface, clip);\
149 func;\
153 #define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) {\
154 double _x = (x);\
155 double _y = (y);\
156 (ret_x) = (_x * (m).xx + (m).x0);\
157 (ret_y) = (_y * (m).yy + (m).y0);\
160 #define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) {\
161 double _x = (x);\
162 double _y = (y);\
163 (ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0);\
164 (ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0);\
167 /* XXX: A1 has a different bits ordering in cairo.
168 * Probably we should drop it.
171 static cairo_content_t
172 _directfb_format_to_content (DFBSurfacePixelFormat format)
174 if (DFB_PIXELFORMAT_HAS_ALPHA (format)) {
175 if (DFB_COLOR_BITS_PER_PIXEL (format))
176 return CAIRO_CONTENT_COLOR_ALPHA;
178 return CAIRO_CONTENT_ALPHA;
181 return CAIRO_CONTENT_COLOR;
184 static inline DFBSurfacePixelFormat
185 _cairo_to_directfb_format (cairo_format_t format)
187 switch (format) {
188 case CAIRO_FORMAT_RGB24:
189 return DSPF_RGB32;
190 case CAIRO_FORMAT_ARGB32:
191 return DSPF_ARGB;
192 case CAIRO_FORMAT_A8:
193 return DSPF_A8;
194 case CAIRO_FORMAT_A1:
195 return DSPF_A1;
196 default:
197 break;
200 return -1;
203 static inline cairo_format_t
204 _directfb_to_cairo_format (DFBSurfacePixelFormat format)
206 switch (format) {
207 case DSPF_RGB32:
208 return CAIRO_FORMAT_RGB24;
209 case DSPF_ARGB:
210 return CAIRO_FORMAT_ARGB32;
211 case DSPF_A8:
212 return CAIRO_FORMAT_A8;
213 case DSPF_A1:
214 return CAIRO_FORMAT_A1;
215 default:
216 break;
219 return -1;
222 static cairo_bool_t
223 _directfb_get_operator (cairo_operator_t operator,
224 DFBSurfaceBlendFunction *ret_srcblend,
225 DFBSurfaceBlendFunction *ret_dstblend)
227 DFBSurfaceBlendFunction srcblend = DSBF_ONE;
228 DFBSurfaceBlendFunction dstblend = DSBF_ZERO;
230 switch (operator) {
231 case CAIRO_OPERATOR_CLEAR:
232 srcblend = DSBF_ZERO;
233 dstblend = DSBF_ZERO;
234 break;
235 case CAIRO_OPERATOR_SOURCE:
236 srcblend = DSBF_ONE;
237 dstblend = DSBF_ZERO;
238 break;
239 case CAIRO_OPERATOR_OVER:
240 srcblend = DSBF_ONE;
241 dstblend = DSBF_INVSRCALPHA;
242 break;
243 case CAIRO_OPERATOR_IN:
244 srcblend = DSBF_DESTALPHA;
245 dstblend = DSBF_ZERO;
246 break;
247 case CAIRO_OPERATOR_OUT:
248 srcblend = DSBF_INVDESTALPHA;
249 dstblend = DSBF_ZERO;
250 break;
251 case CAIRO_OPERATOR_ATOP:
252 srcblend = DSBF_DESTALPHA;
253 dstblend = DSBF_INVSRCALPHA;
254 break;
255 case CAIRO_OPERATOR_DEST:
256 srcblend = DSBF_ZERO;
257 dstblend = DSBF_ONE;
258 break;
259 case CAIRO_OPERATOR_DEST_OVER:
260 srcblend = DSBF_INVDESTALPHA;
261 dstblend = DSBF_ONE;
262 break;
263 case CAIRO_OPERATOR_DEST_IN:
264 srcblend = DSBF_ZERO;
265 dstblend = DSBF_SRCALPHA;
266 break;
267 case CAIRO_OPERATOR_DEST_OUT:
268 srcblend = DSBF_ZERO;
269 dstblend = DSBF_INVSRCALPHA;
270 break;
271 case CAIRO_OPERATOR_DEST_ATOP:
272 srcblend = DSBF_INVDESTALPHA;
273 dstblend = DSBF_SRCALPHA;
274 break;
275 case CAIRO_OPERATOR_XOR:
276 srcblend = DSBF_INVDESTALPHA;
277 dstblend = DSBF_INVSRCALPHA;
278 break;
279 case CAIRO_OPERATOR_ADD:
280 srcblend = DSBF_ONE;
281 dstblend = DSBF_ONE;
282 break;
283 case CAIRO_OPERATOR_SATURATE:
284 /* XXX This does not work. */
285 #if 0
286 srcblend = DSBF_SRCALPHASAT;
287 dstblend = DSBF_ONE;
288 break;
289 #endif
290 default:
291 return FALSE;
294 *ret_srcblend = srcblend;
295 *ret_dstblend = dstblend;
297 return TRUE;
300 static cairo_status_t
301 _directfb_buffer_surface_create (IDirectFB *dfb,
302 DFBSurfacePixelFormat format,
303 int width,
304 int height,
305 IDirectFBSurface **out)
307 IDirectFBSurface *buffer;
308 DFBSurfaceDescription dsc;
309 DFBResult ret;
311 dsc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
312 dsc.caps = DSCAPS_PREMULTIPLIED;
313 dsc.width = width;
314 dsc.height = height;
315 dsc.pixelformat = format;
317 ret = dfb->CreateSurface (dfb, &dsc, &buffer);
318 if (ret) {
319 DirectFBError ("IDirectFB::CreateSurface()", ret);
320 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
323 *out = buffer;
324 return CAIRO_STATUS_SUCCESS;
327 static cairo_status_t
328 _directfb_acquire_surface (cairo_directfb_surface_t *surface,
329 cairo_rectangle_int_t *intrest_rec,
330 cairo_image_surface_t **image_out,
331 cairo_rectangle_int_t *image_rect_out,
332 void **image_extra,
333 DFBSurfaceLockFlags lock_flags)
335 IDirectFBSurface *buffer = NULL;
336 DFBRectangle source_rect;
337 cairo_surface_t *image;
338 cairo_format_t cairo_format;
339 cairo_status_t status;
340 void *data;
341 int pitch;
343 if (surface->format == (cairo_format_t) -1 ||
344 (lock_flags & DSLF_WRITE && surface->has_clip))
346 DFBSurfaceCapabilities caps;
348 if (intrest_rec) {
349 source_rect.x = intrest_rec->x;
350 source_rect.y = intrest_rec->y;
351 source_rect.w = intrest_rec->width;
352 source_rect.h = intrest_rec->height;
353 } else {
354 source_rect.x = 0;
355 source_rect.y = 0;
356 surface->dfbsurface->GetSize (surface->dfbsurface,
357 &source_rect.w, &source_rect.h);
360 if (surface->tmpsurface) {
361 int w, h;
362 surface->tmpsurface->GetSize (surface->tmpsurface, &w, &h);
363 if (w < source_rect.w || h < source_rect.h) {
364 surface->tmpsurface->Release (surface->tmpsurface);
365 surface->tmpsurface = NULL;
369 cairo_format = _cairo_format_from_content (surface->content);
370 if (!surface->tmpsurface) {
371 D_DEBUG_AT (CairoDFB_Acquire, "Allocating buffer for surface %p.\n", surface);
373 status =
374 _directfb_buffer_surface_create (surface->dfb,
375 _cairo_to_directfb_format (cairo_format),
376 source_rect.w, source_rect.h,
377 &surface->tmpsurface);
378 if (status)
379 goto ERROR;
381 buffer = surface->tmpsurface;
383 /* surface->dfbsurface->GetCapabilities (surface->dfbsurface, &caps);
384 if (caps & DSCAPS_FLIPPING) {
385 DFBRegion region = { .x1 = source_rect.x, .y1 = source_rect.y,
386 .x2 = source_rect.x + source_rect.w - 1,
387 .y2 = source_rect.y + source_rect.h - 1 };
388 surface->dfbsurface->Flip (surface->dfbsurface, &region, DSFLIP_BLIT);
389 } */
390 buffer->Blit (buffer, surface->dfbsurface, &source_rect, 0, 0);
391 } else {
392 /*might be a subsurface get the offset*/
393 surface->dfbsurface->GetVisibleRectangle (surface->dfbsurface, &source_rect);
394 cairo_format = surface->format;
395 buffer = surface->dfbsurface;
398 if (buffer->Lock (buffer, lock_flags, &data, &pitch)) {
399 D_DEBUG_AT (CairoDFB_Acquire, "Couldn't lock surface!\n");
400 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
401 goto ERROR;
404 image = cairo_image_surface_create_for_data (data, cairo_format,
405 source_rect.w, source_rect.h,
406 pitch);
407 status = image->status;
408 if (status)
409 goto ERROR;
411 if (image_rect_out) {
412 image_rect_out->x = source_rect.x;
413 image_rect_out->y = source_rect.y;
414 image_rect_out->width = source_rect.w;
415 image_rect_out->height = source_rect.h;
416 } else {
417 /* lock for read */
418 /* might be a subsurface */
419 if (buffer == surface->dfbsurface) {
420 cairo_surface_set_device_offset (image,
421 source_rect.x, source_rect.y);
425 *image_extra = buffer;
426 *image_out = (cairo_image_surface_t *) image;
427 return CAIRO_STATUS_SUCCESS;
429 ERROR:
430 if (buffer) {
431 buffer->Unlock (buffer);
432 if (buffer != surface->dfbsurface)
433 buffer->Release (buffer);
435 return status;
438 static cairo_surface_t *
439 _cairo_directfb_surface_create_similar (void *abstract_src,
440 cairo_content_t content,
441 int width,
442 int height)
444 cairo_directfb_surface_t *source = abstract_src;
445 cairo_directfb_surface_t *surface;
446 cairo_format_t format;
447 cairo_status_t status;
449 D_DEBUG_AT (CairoDFB_Surface,
450 "%s( src=%p, content=0x%x, width=%d, height=%d).\n",
451 __FUNCTION__, source, content, width, height);
453 width = (width <= 0) ? 1 : width;
454 height = (height<= 0) ? 1 : height;
456 format = _cairo_format_from_content (content);
457 surface = calloc (1, sizeof (cairo_directfb_surface_t));
458 if (surface == NULL)
459 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
461 surface->dfb = source->dfb;
463 if (width < 8 || height < 8) {
464 IDirectFBSurface *tmp;
465 DFBRectangle rect = { .x=0, .y=0, .w=width, .h=height };
467 /* Some cards (e.g. Matrox) don't support surfaces smaller than 8x8 */
468 status = _directfb_buffer_surface_create (surface->dfb,
469 _cairo_to_directfb_format (format),
470 MAX (width, 8), MAX (height, 8),
471 &tmp);
472 if (status) {
473 free (surface);
474 return _cairo_surface_create_in_error (status);
477 tmp->GetSubSurface (tmp, &rect, &surface->dfbsurface);
478 tmp->Release (tmp);
479 } else {
480 status =
481 _directfb_buffer_surface_create (surface->dfb,
482 _cairo_to_directfb_format (format),
483 width, height,
484 &surface->dfbsurface);
485 if (status) {
486 free (surface);
487 return _cairo_surface_create_in_error (status);
491 _cairo_surface_init (&surface->base,
492 &_cairo_directfb_surface_backend,
493 content);
494 surface->format = format;
495 surface->content = content;
496 surface->width = width;
497 surface->height = height;
498 surface->local = TRUE;
499 surface->blit_premultiplied = TRUE;
501 return &surface->base;
504 static cairo_status_t
505 _cairo_directfb_surface_finish (void *data)
507 cairo_directfb_surface_t *surface = (cairo_directfb_surface_t *)data;
509 D_DEBUG_AT (CairoDFB_Surface, "%s( surface=%p ).\n", __FUNCTION__, surface);
511 if (surface->clips) {
512 free (surface->clips);
513 surface->clips = NULL;
514 surface->n_clips = 0;
517 if (surface->tmpsurface) {
518 surface->tmpsurface->Release (surface->tmpsurface);
519 surface->tmpsurface = NULL;
522 if (surface->dfbsurface) {
523 surface->dfbsurface->Release (surface->dfbsurface);
524 surface->dfbsurface = NULL;
527 if (surface->dfb)
528 surface->dfb = NULL;
530 return CAIRO_STATUS_SUCCESS;
533 static cairo_status_t
534 _cairo_directfb_surface_acquire_source_image (void *abstract_surface,
535 cairo_image_surface_t **image_out,
536 void **image_extra)
538 cairo_directfb_surface_t *surface = abstract_surface;
540 D_DEBUG_AT (CairoDFB_Acquire,
541 "%s( surface=%p ).\n", __FUNCTION__, surface);
543 return _directfb_acquire_surface (surface, NULL, image_out,
544 NULL, image_extra, DSLF_READ);
547 static void
548 _cairo_directfb_surface_release_source_image (void *abstract_surface,
549 cairo_image_surface_t *image,
550 void *image_extra)
552 IDirectFBSurface *buffer = image_extra;
554 D_DEBUG_AT (CairoDFB_Acquire,
555 "%s( surface=%p ).\n", __FUNCTION__, surface);
557 buffer->Unlock (buffer);
559 cairo_surface_destroy (&image->base);
562 static cairo_status_t
563 _cairo_directfb_surface_acquire_dest_image (void *abstract_surface,
564 cairo_rectangle_int_t *interest_rect,
565 cairo_image_surface_t **image_out,
566 cairo_rectangle_int_t *image_rect_out,
567 void **image_extra)
569 cairo_directfb_surface_t *surface = abstract_surface;
571 D_DEBUG_AT (CairoDFB_Acquire,
572 "%s( surface=%p (%dx%d), interest_rect={ %u %u %u %u } ).\n",
573 __FUNCTION__, surface, surface->width, surface->height,
574 interest_rect ? interest_rect->x : 0,
575 interest_rect ? interest_rect->y : 0,
576 interest_rect ? interest_rect->width : (unsigned) surface->width,
577 interest_rect ? interest_rect->height : (unsigned) surface->height);
579 return _directfb_acquire_surface (surface, interest_rect, image_out,
580 image_rect_out, image_extra,
581 DSLF_READ | DSLF_WRITE);
584 static void
585 _cairo_directfb_surface_release_dest_image (void *abstract_surface,
586 cairo_rectangle_int_t *interest_rect,
587 cairo_image_surface_t *image,
588 cairo_rectangle_int_t *image_rect,
589 void *image_extra)
591 cairo_directfb_surface_t *surface = abstract_surface;
592 IDirectFBSurface *buffer = image_extra;
594 D_DEBUG_AT (CairoDFB_Acquire,
595 "%s( surface=%p ).\n", __FUNCTION__, surface);
597 buffer->Unlock (buffer);
599 if (surface->dfbsurface != buffer) {
600 DFBRegion region = {
601 .x1 = interest_rect->x,
602 .y1 = interest_rect->y,
603 .x2 = interest_rect->x + interest_rect->width - 1,
604 .y2 = interest_rect->y + interest_rect->height - 1
606 surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, DSBLIT_NOFX);
607 RUN_CLIPPED (surface, &region,
608 surface->dfbsurface->Blit (surface->dfbsurface,
609 buffer, NULL,
610 image_rect->x, image_rect->y));
613 cairo_surface_destroy (&image->base);
616 static cairo_status_t
617 _cairo_directfb_surface_clone_similar (void *abstract_surface,
618 cairo_surface_t *src,
619 int src_x,
620 int src_y,
621 int width,
622 int height,
623 int *clone_offset_x,
624 int *clone_offset_y,
625 cairo_surface_t **clone_out)
627 cairo_directfb_surface_t *surface = abstract_surface;
628 cairo_directfb_surface_t *clone;
630 D_DEBUG_AT (CairoDFB_Surface,
631 "%s( surface=%p, src=%p ).\n", __FUNCTION__, surface, src);
633 if (src->backend == surface->base.backend) {
634 *clone_offset_x = 0;
635 *clone_offset_y = 0;
636 *clone_out = cairo_surface_reference (src);
638 return CAIRO_STATUS_SUCCESS;
639 } else if (_cairo_surface_is_image (src)) {
640 cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
641 unsigned char *dst, *src = image_src->data;
642 int pitch;
643 int i, j;
644 DFBResult ret;
646 clone = (cairo_directfb_surface_t *)
647 _cairo_directfb_surface_create_similar (surface,
648 _cairo_content_from_format (image_src->format),
649 width, height);
650 if (clone == NULL)
651 return CAIRO_INT_STATUS_UNSUPPORTED;
652 if (clone->base.status)
653 return clone->base.status;
655 ret = clone->dfbsurface->Lock (clone->dfbsurface,
656 DSLF_WRITE, (void *)&dst, &pitch);
657 if (ret) {
658 DirectFBError ("IDirectFBSurface::Lock()", ret);
659 cairo_surface_destroy (&clone->base);
660 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
663 src += image_src->stride * src_y;
664 if (image_src->format == CAIRO_FORMAT_A1) {
665 /* A1 -> A8 */
666 dst -= src_x;
667 for (i = 0; i < height; i++) {
668 for (j = src_x; j < src_x + width; j++)
669 dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00;
670 dst += pitch;
671 src += image_src->stride;
673 } else {
674 int len;
676 if (image_src->format == CAIRO_FORMAT_A8) {
677 src += src_x;
678 len = width;
679 } else {
680 src += src_x * 4;
681 len = width * 4;
684 for (i = 0; i < height; i++) {
685 direct_memcpy (dst, src, len);
686 dst += pitch;
687 src += image_src->stride;
691 clone->dfbsurface->Unlock (clone->dfbsurface);
693 *clone_offset_x = src_x;
694 *clone_offset_y = src_y;
695 *clone_out = &clone->base;
696 return CAIRO_STATUS_SUCCESS;
699 return CAIRO_INT_STATUS_UNSUPPORTED;
702 #if DFB_COMPOSITE || DFB_COMPOSITE_TRAPEZOIDS
703 static cairo_int_status_t
704 _directfb_prepare_composite (cairo_directfb_surface_t *dst,
705 cairo_pattern_t *src_pattern,
706 cairo_pattern_t *mask_pattern,
707 cairo_operator_t op,
708 int *src_x, int *src_y,
709 int *mask_x, int *mask_y,
710 unsigned int width,
711 unsigned int height,
712 cairo_directfb_surface_t **ret_src,
713 cairo_surface_attributes_t *ret_src_attr)
715 cairo_directfb_surface_t *src;
716 cairo_surface_attributes_t src_attr;
717 cairo_status_t status;
718 DFBSurfaceBlittingFlags flags;
719 DFBSurfaceBlendFunction sblend;
720 DFBSurfaceBlendFunction dblend;
721 const cairo_color_t *color;
723 /* XXX Unbounded operators are not handled correctly */
724 if (! _cairo_operator_bounded_by_source (op))
725 return CAIRO_INT_STATUS_UNSUPPORTED;
727 if (! _directfb_get_operator (op, &sblend, &dblend))
728 return CAIRO_INT_STATUS_UNSUPPORTED;
730 if (mask_pattern) {
731 cairo_solid_pattern_t *pattern;
733 return CAIRO_INT_STATUS_UNSUPPORTED;
734 if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
735 cairo_pattern_t *tmp;
736 int tmp_x, tmp_y;
738 if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID ||
739 sblend == DSBF_INVDESTALPHA) /* Doesn't work correctly */
740 return CAIRO_INT_STATUS_UNSUPPORTED;
742 D_DEBUG_AT (CairoDFB_Render, "Replacing src pattern by mask pattern.\n");
744 tmp = src_pattern;
745 tmp_x = *src_x; tmp_y = *src_y;
747 src_pattern = mask_pattern;
748 *src_x = *mask_x; *src_y = *mask_y;
750 mask_pattern = tmp;
751 *mask_x = tmp_x; *mask_y = tmp_y;
753 if (sblend == DSBF_ONE) {
754 sblend = DSBF_SRCALPHA;
755 /*dblend = DSBF_INVSRCALPHA;*/
759 color = &((cairo_solid_pattern_t *) mask_pattern)->color;
760 } else {
761 color = _cairo_stock_color (CAIRO_STOCK_WHITE);
764 /* XXX DirectFB currently does not support filtering, so force NEAREST
765 * in order to hit optimisations inside core.
767 src_pattern->filter = CAIRO_FILTER_NEAREST;
769 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
770 *src_x, *src_y, width, height,
771 (cairo_surface_t **) &src,
772 &src_attr);
773 if (status)
774 return status;
776 if (src->base.backend != &_cairo_directfb_surface_backend ||
777 src->dfb != dst->dfb)
779 _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
780 return CAIRO_INT_STATUS_UNSUPPORTED;
783 if (src->content == CAIRO_CONTENT_COLOR) {
784 if (sblend == DSBF_SRCALPHA)
785 sblend = DSBF_ONE;
786 else if (sblend == DSBF_INVSRCALPHA)
787 sblend = DSBF_ZERO;
789 if (dblend == DSBF_SRCALPHA)
790 dblend = DSBF_ONE;
791 else if (dblend == DSBF_INVSRCALPHA)
792 dblend = DSBF_ZERO;
795 if (dst->content == CAIRO_CONTENT_COLOR) {
796 if (sblend == DSBF_DESTALPHA)
797 sblend = DSBF_ONE;
798 else if (sblend == DSBF_INVDESTALPHA)
799 sblend = DSBF_ZERO;
801 if (dblend == DSBF_DESTALPHA)
802 dblend = DSBF_ONE;
803 else if (dblend == DSBF_INVDESTALPHA)
804 dblend = DSBF_ZERO;
807 flags = (sblend == DSBF_ONE && dblend == DSBF_ZERO)
808 ? DSBLIT_NOFX : DSBLIT_BLEND_ALPHACHANNEL;
809 if (! CAIRO_COLOR_IS_OPAQUE (color))
810 flags |= DSBLIT_BLEND_COLORALPHA;
811 if (! _cairo_color_equal (color, _cairo_stock_color (CAIRO_STOCK_WHITE)))
812 flags |= DSBLIT_COLORIZE;
814 dst->dfbsurface->SetBlittingFlags (dst->dfbsurface, flags);
816 if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) {
817 dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
818 dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
821 if (flags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_COLORIZE)) {
822 if (dst->blit_premultiplied) {
823 dst->dfbsurface->SetColor (dst->dfbsurface,
824 color->red_short >> 8,
825 color->green_short >> 8,
826 color->blue_short >> 8,
827 color->alpha_short >> 8);
828 } else {
829 dst->dfbsurface->SetColor (dst->dfbsurface,
830 color->red * 0xff,
831 color->green * 0xff,
832 color->blue * 0xff,
833 color->alpha * 0xff);
837 *ret_src = src;
838 *ret_src_attr = src_attr;
840 return CAIRO_STATUS_SUCCESS;
843 static void
844 _directfb_finish_composite (cairo_directfb_surface_t *dst,
845 cairo_pattern_t *src_pattern,
846 cairo_surface_t *src,
847 cairo_surface_attributes_t *src_attr)
849 _cairo_pattern_release_surface (src_pattern, src, src_attr);
851 #endif /* DFB_COMPOSITE || DFB_COMPOSITE_TRAPEZOIDS */
853 #if DFB_COMPOSITE
854 static DFBAccelerationMask
855 _directfb_categorize_operation (cairo_surface_attributes_t *src_attr)
857 cairo_matrix_t *m = &src_attr->matrix;
859 if (m->xy != 0 || m->yx != 0 || m->xx < 0 || m->yy < 0) {
860 if (src_attr->extend != CAIRO_EXTEND_NONE)
861 return DFXL_NONE;
863 return DFXL_TEXTRIANGLES;
866 if (m->xx != 1 || m->yy != 1) {
867 if (src_attr->extend != CAIRO_EXTEND_NONE)
868 return DFXL_NONE;
870 return DFXL_STRETCHBLIT;
873 switch (src_attr->extend) {
874 case CAIRO_EXTEND_NONE:
875 case CAIRO_EXTEND_REPEAT:
876 if (_cairo_matrix_is_integer_translation (&src_attr->matrix,
877 NULL, NULL))
879 return DFXL_BLIT;
881 else
883 return DFXL_STRETCHBLIT;
886 default:
887 case CAIRO_EXTEND_REFLECT:
888 case CAIRO_EXTEND_PAD:
889 return DFXL_NONE;
893 static cairo_int_status_t
894 _cairo_directfb_surface_composite (cairo_operator_t op,
895 cairo_pattern_t *src_pattern,
896 cairo_pattern_t *mask_pattern,
897 void *abstract_dst,
898 int src_x, int src_y,
899 int mask_x, int mask_y,
900 int dst_x, int dst_y,
901 unsigned int width,
902 unsigned int height)
904 cairo_directfb_surface_t *dst = abstract_dst;
905 cairo_directfb_surface_t *src;
906 cairo_surface_attributes_t src_attr;
907 cairo_bool_t is_integer_translation;
908 DFBAccelerationMask accel, mask;
909 cairo_int_status_t status;
910 int tx, ty;
912 D_DEBUG_AT (CairoDFB_Render,
913 "%s( op=%d, src_pattern=%p, mask_pattern=%p, dst=%p,"
914 " src_x=%d, src_y=%d, mask_x=%d, mask_y=%d, dst_x=%d,"
915 " dst_y=%d, width=%u, height=%u ).\n",
916 __FUNCTION__, op, src_pattern, mask_pattern, dst,
917 src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
919 status = _directfb_prepare_composite (dst, src_pattern, mask_pattern, op,
920 &src_x, &src_y, &mask_x, &mask_y,
921 width, height, &src, &src_attr);
922 if (status)
923 return status;
925 accel = _directfb_categorize_operation (&src_attr);
926 if (accel == DFXL_NONE) {
927 _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
928 return CAIRO_INT_STATUS_UNSUPPORTED;
931 dst->dfbsurface->GetAccelerationMask (dst->dfbsurface,
932 src->dfbsurface,
933 &mask);
934 if ((mask & accel) == 0) {
935 D_DEBUG_AT (CairoDFB_Render, "No acceleration (%08x)!\n", accel);
936 if (accel != DFXL_BLIT) {
937 _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
938 return CAIRO_INT_STATUS_UNSUPPORTED;
942 src_x += src_attr.x_offset;
943 src_y += src_attr.y_offset;
945 switch (accel) {
946 case DFXL_BLIT:
948 DFBRectangle sr;
950 is_integer_translation =
951 _cairo_matrix_is_integer_translation (&src_attr.matrix,
952 &tx, &ty);
953 assert (is_integer_translation);
955 sr.x = src_x + tx;
956 sr.y = src_y + ty;
957 sr.w = width;
958 sr.h = height;
960 if (src_attr.extend == CAIRO_EXTEND_NONE) {
961 D_DEBUG_AT (CairoDFB_Render, "Running Blit().\n");
963 RUN_CLIPPED (dst, NULL,
964 dst->dfbsurface->Blit (dst->dfbsurface,
965 src->dfbsurface,
966 &sr,
967 dst_x, dst_y));
968 } else if (src_attr.extend == CAIRO_EXTEND_REPEAT) {
969 DFBRegion clip;
971 clip.x1 = dst_x;
972 clip.y1 = dst_y;
973 clip.x2 = dst_x + width - 1;
974 clip.y2 = dst_y + height - 1;
976 D_DEBUG_AT (CairoDFB_Render, "Running TileBlit().\n");
978 RUN_CLIPPED (dst, &clip,
979 dst->dfbsurface->TileBlit (dst->dfbsurface,
980 src->dfbsurface,
981 &sr,
982 dst_x, dst_y));
984 break;
987 case DFXL_STRETCHBLIT:
989 DFBRectangle sr, dr;
990 double x1, y1, x2, y2;
992 TRANSFORM_POINT2X (src_attr.matrix,
993 src_x, src_y, x1, y1);
994 TRANSFORM_POINT2X (src_attr.matrix,
995 src_x+width, src_y+height, x2, y2);
997 sr.x = floor (x1);
998 sr.y = floor (y1);
999 sr.w = ceil (x2) - sr.x;
1000 sr.h = ceil (y2) - sr.y;
1002 dr.x = dst_x;
1003 dr.y = dst_y;
1004 dr.w = width;
1005 dr.h = height;
1007 D_DEBUG_AT (CairoDFB_Render, "Running StretchBlit().\n");
1009 RUN_CLIPPED (dst, NULL,
1010 dst->dfbsurface->StretchBlit (dst->dfbsurface,
1011 src->dfbsurface, &sr, &dr));
1012 break;
1015 case DFXL_TEXTRIANGLES:
1017 DFBRegion clip;
1018 DFBVertex v[4];
1019 float x1, y1, x2, y2;
1020 int w, h;
1022 status = cairo_matrix_invert (&src_attr.matrix);
1023 /* guaranteed by cairo_pattern_set_matrix (); */
1024 assert (status == CAIRO_STATUS_SUCCESS);
1026 x1 = src_x;
1027 y1 = src_y;
1028 x2 = width + x1;
1029 y2 = height + y1;
1031 src->dfbsurface->GetSize (src->dfbsurface, &w, &h);
1033 TRANSFORM_POINT3X (src_attr.matrix,
1034 x1, y1, v[0].x, v[0].y);
1035 v[0].z = 0;
1036 v[0].w = 1;
1037 v[0].s = x1 / w;
1038 v[0].t = y1 / h;
1040 TRANSFORM_POINT3X (src_attr.matrix,
1041 x2, y1, v[1].x, v[1].y);
1042 v[1].z = 0;
1043 v[1].w = 1;
1044 v[1].s = x2 / w;
1045 v[1].t = y1 / h;
1047 TRANSFORM_POINT3X (src_attr.matrix,
1048 x2, y2, v[2].x, v[2].y);
1049 v[2].z = 0;
1050 v[2].w = 1;
1051 v[2].s = x2 / w;
1052 v[2].t = y2 / h;
1054 TRANSFORM_POINT3X (src_attr.matrix,
1055 x1, y2, v[3].x, v[3].y);
1056 v[3].z = 0;
1057 v[3].w = 1;
1058 v[3].s = x1 / w;
1059 v[3].t = y2 / h;
1061 clip.x1 = dst_x;
1062 clip.y1 = dst_y;
1063 clip.x2 = dst_x + width - 1;
1064 clip.y2 = dst_y + height - 1;
1066 D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
1068 RUN_CLIPPED (dst, &clip,
1069 dst->dfbsurface->TextureTriangles (dst->dfbsurface,
1070 src->dfbsurface, v, NULL, 4, DTTF_FAN));
1071 break;
1074 default:
1075 D_BUG ("Unexpected operation");
1076 break;
1079 _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
1081 return status;
1083 #endif /* DFB_COMPOSITE */
1085 #if DFB_RECTANGLES
1086 static cairo_int_status_t
1087 _cairo_directfb_surface_fill_rectangles (void *abstract_surface,
1088 cairo_operator_t op,
1089 const cairo_color_t *color,
1090 cairo_rectangle_int_t *rects,
1091 int n_rects)
1093 cairo_directfb_surface_t *dst = abstract_surface;
1094 DFBSurfaceDrawingFlags flags;
1095 DFBSurfaceBlendFunction sblend;
1096 DFBSurfaceBlendFunction dblend;
1097 DFBRectangle r[n_rects];
1098 int i;
1100 D_DEBUG_AT (CairoDFB_Render,
1101 "%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n",
1102 __FUNCTION__, dst, op, color, rects, n_rects);
1104 if (! _cairo_operator_bounded_by_source (op))
1105 return CAIRO_INT_STATUS_UNSUPPORTED;
1107 if (! _directfb_get_operator (op, &sblend, &dblend))
1108 return CAIRO_INT_STATUS_UNSUPPORTED;
1110 if (CAIRO_COLOR_IS_OPAQUE (color)) {
1111 if (sblend == DSBF_SRCALPHA)
1112 sblend = DSBF_ONE;
1113 else if (sblend == DSBF_INVSRCALPHA)
1114 sblend = DSBF_ZERO;
1116 if (dblend == DSBF_SRCALPHA)
1117 dblend = DSBF_ONE;
1118 else if (dblend == DSBF_INVSRCALPHA)
1119 dblend = DSBF_ZERO;
1121 if (dst->content == CAIRO_CONTENT_COLOR) {
1122 if (sblend == DSBF_DESTALPHA)
1123 sblend = DSBF_ONE;
1124 else if (sblend == DSBF_INVDESTALPHA)
1125 sblend = DSBF_ZERO;
1127 if (dblend == DSBF_DESTALPHA)
1128 dblend = DSBF_ONE;
1129 else if (dblend == DSBF_INVDESTALPHA)
1130 dblend = DSBF_ZERO;
1133 flags = (sblend == DSBF_ONE && dblend == DSBF_ZERO) ? DSDRAW_NOFX : DSDRAW_BLEND;
1134 dst->dfbsurface->SetDrawingFlags (dst->dfbsurface, flags);
1135 if (flags & DSDRAW_BLEND) {
1136 dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
1137 dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
1140 dst->dfbsurface->SetColor (dst->dfbsurface,
1141 color->red_short >> 8,
1142 color->green_short >> 8,
1143 color->blue_short >> 8,
1144 color->alpha_short >> 8);
1146 for (i = 0; i < n_rects; i++) {
1147 r[i].x = rects[i].x;
1148 r[i].y = rects[i].y;
1149 r[i].w = rects[i].width;
1150 r[i].h = rects[i].height;
1153 RUN_CLIPPED (dst, NULL,
1154 dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects));
1156 return CAIRO_STATUS_SUCCESS;
1158 #endif
1160 #if DFB_COMPOSITE_TRAPEZOIDS
1161 static cairo_int_status_t
1162 _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
1163 cairo_pattern_t *pattern,
1164 void *abstract_dst,
1165 cairo_antialias_t antialias,
1166 int src_x, int src_y,
1167 int dst_x, int dst_y,
1168 unsigned int width,
1169 unsigned int height,
1170 cairo_trapezoid_t *traps,
1171 int num_traps)
1173 cairo_directfb_surface_t *dst = abstract_dst;
1174 cairo_directfb_surface_t *src;
1175 cairo_surface_attributes_t src_attr;
1176 cairo_status_t status;
1177 DFBAccelerationMask accel;
1179 D_DEBUG_AT (CairoDFB_Render,
1180 "%s( op=%d, pattern=%p, dst=%p, antialias=%d,"
1181 " src_x=%d, src_y=%d, dst_x=%d, dst_y=%d,"
1182 " width=%u, height=%u, traps=%p, num_traps=%d ).\n",
1183 __FUNCTION__, op, pattern, dst, antialias,
1184 src_x, src_y, dst_x, dst_y, width, height, traps, num_traps);
1186 if (antialias != CAIRO_ANTIALIAS_NONE)
1187 return CAIRO_INT_STATUS_UNSUPPORTED;
1189 /* Textures are not supported yet. */
1190 if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
1191 return CAIRO_INT_STATUS_UNSUPPORTED;
1193 status = _directfb_prepare_composite (dst, pattern, NULL, op,
1194 &src_x, &src_y, NULL, NULL,
1195 width, height, &src, &src_attr);
1196 if (status)
1197 return status;
1199 dst->dfbsurface->GetAccelerationMask (dst->dfbsurface,
1200 src->dfbsurface,
1201 &accel);
1203 status = CAIRO_INT_STATUS_UNSUPPORTED;
1205 if (accel & DFXL_TEXTRIANGLES) {
1206 DFBVertex vertex[6*num_traps];
1207 DFBVertex *v = &vertex[0];
1208 int n = 0;
1210 #define ADD_TRI_V(V, X, Y) do { \
1211 (V)->x = (X); (V)->y = (Y); (V)->w = 1; (V)->z = (V)->s = (V)->t = 0; \
1212 } while (0)
1213 #define ADD_TRI(id, x1, y1, x2, y2, x3, y3) do {\
1214 const int p = (id)*3;\
1215 ADD_TRI_V (v+p+0, x1, y1); \
1216 ADD_TRI_V (v+p+1, x2, y2); \
1217 ADD_TRI_V (v+p+2, x3, y3); \
1218 } while (0)
1219 while (num_traps--) {
1220 double lx1, ly1, lx2, ly2;
1221 double rx1, ry1, rx2, ry2;
1223 lx1 = _cairo_fixed_to_double (traps->left.p1.x);
1224 ly1 = _cairo_fixed_to_double (traps->left.p1.y);
1225 lx2 = _cairo_fixed_to_double (traps->left.p2.x);
1226 ly2 = _cairo_fixed_to_double (traps->left.p2.y);
1227 rx1 = _cairo_fixed_to_double (traps->right.p1.x);
1228 ry1 = _cairo_fixed_to_double (traps->right.p1.y);
1229 rx2 = _cairo_fixed_to_double (traps->right.p2.x);
1230 ry2 = _cairo_fixed_to_double (traps->right.p2.y);
1232 if (traps->left.p1.y < traps->top) {
1233 double y = _cairo_fixed_to_double (traps->top);
1234 if (lx2 != lx1)
1235 lx1 = (y - ly1) * (lx2 - lx1) / (ly2 - ly1) + lx1;
1236 ly1 = y;
1238 if (traps->left.p2.y > traps->bottom) {
1239 double y = _cairo_fixed_to_double (traps->bottom);
1240 if (lx2 != lx1)
1241 lx2 = (y - ly1) * (lx2 - lx1) / (ly2 - ly1) + lx1;
1242 ly2 = y;
1245 if (traps->right.p1.y < traps->top) {
1246 double y = _cairo_fixed_to_double (traps->top);
1247 if (rx2 != rx1)
1248 rx1 = (y - ry1) * (rx2 - rx1) / (ry2 - ry1) + rx1;
1249 ry1 = y;
1251 if (traps->right.p2.y > traps->bottom) {
1252 double y = _cairo_fixed_to_double (traps->bottom);
1253 if (rx2 != rx1)
1254 rx2 = (y - ry1) * (rx2 - rx1) / (ry2 - ry1) + rx1;
1255 ry2 = y;
1258 if (lx1 == rx1 && ly1 == ry1) {
1259 ADD_TRI (0, lx2, ly2, lx1, ly1, rx2, ry2);
1260 v += 3;
1261 n += 3;
1262 } else if (lx2 == rx2 && ly2 == ry2) {
1263 ADD_TRI (0, lx1, ly1, lx2, ly2, rx1, ry1);
1264 v += 3;
1265 n += 3;
1266 } else {
1267 ADD_TRI (0, lx1, ly1, rx1, ry1, lx2, ly2);
1268 ADD_TRI (1, lx2, ly2, rx1, ry1, rx2, ry2);
1269 v += 6;
1270 n += 6;
1273 traps++;
1275 #undef ADD_TRI
1276 #undef ADD_TRI_V
1278 D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
1280 RUN_CLIPPED (dst, NULL,
1281 dst->dfbsurface->TextureTriangles (dst->dfbsurface,
1282 src->dfbsurface,
1283 vertex, NULL, n,
1284 DTTF_LIST));
1286 status = CAIRO_STATUS_SUCCESS;
1289 _directfb_finish_composite (dst, pattern, &src->base, &src_attr);
1291 return status;
1293 #endif /* DFB_COMPOSITE_TRAPEZOIDS */
1295 static cairo_int_status_t
1296 _cairo_directfb_surface_set_clip_region (void *abstract_surface,
1297 cairo_region_t *region)
1299 cairo_directfb_surface_t *surface = abstract_surface;
1301 D_DEBUG_AT (CairoDFB_Clip,
1302 "%s( surface=%p, region=%p ).\n",
1303 __FUNCTION__, surface, region);
1305 if (region) {
1306 cairo_box_int_t *boxes;
1307 int n_boxes;
1308 cairo_status_t status;
1309 int i;
1311 surface->has_clip = TRUE;
1313 status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
1314 if (n_boxes == 0)
1315 return CAIRO_STATUS_SUCCESS;
1316 if (status)
1317 return status;
1319 if (surface->n_clips != n_boxes) {
1320 if (surface->clips)
1321 free (surface->clips);
1323 surface->clips = _cairo_malloc_ab (n_boxes, sizeof (DFBRegion));
1324 if (!surface->clips) {
1325 surface->n_clips = 0;
1326 _cairo_region_boxes_fini (region, boxes);
1327 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1330 surface->n_clips = n_boxes;
1333 for (i = 0; i < n_boxes; i++) {
1334 surface->clips[i].x1 = boxes[i].p1.x;
1335 surface->clips[i].y1 = boxes[i].p1.y;
1336 surface->clips[i].x2 = boxes[i].p2.x - 1;
1337 surface->clips[i].y2 = boxes[i].p2.y - 1;
1340 _cairo_region_boxes_fini (region, boxes);
1341 } else {
1342 surface->has_clip = FALSE;
1343 if (surface->clips) {
1344 free (surface->clips);
1345 surface->clips = NULL;
1346 surface->n_clips = 0;
1350 return CAIRO_STATUS_SUCCESS;
1353 static cairo_int_status_t
1354 _cairo_directfb_abstract_surface_get_extents (void *abstract_surface,
1355 cairo_rectangle_int_t *rectangle)
1357 cairo_directfb_surface_t *surface = abstract_surface;
1359 D_DEBUG_AT (CairoDFB_Surface,
1360 "%s( surface=%p, rectangle=%p ).\n",
1361 __FUNCTION__, surface, rectangle);
1363 if (!surface->local) {
1364 surface->dfbsurface->GetSize (surface->dfbsurface,
1365 &surface->width, &surface->height);
1368 rectangle->x = 0;
1369 rectangle->y = 0;
1370 rectangle->width = surface->width;
1371 rectangle->height = surface->height;
1373 return CAIRO_STATUS_SUCCESS;
1376 #if DFB_SHOW_GLYPHS
1377 static cairo_status_t
1378 _directfb_allocate_font_cache (IDirectFB *dfb,
1379 int width, int height,
1380 cairo_directfb_font_cache_t **out)
1382 cairo_directfb_font_cache_t *cache;
1383 cairo_status_t status;
1385 cache = calloc (1, sizeof (cairo_directfb_font_cache_t));
1386 if (cache == NULL)
1387 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1389 cache->dfb = dfb;
1390 status = _directfb_buffer_surface_create (dfb,
1391 _directfb_argb_font ? DSPF_ARGB : DSPF_A8,
1392 width, height,
1393 &cache->dfbsurface);
1394 if (status) {
1395 free (cache);
1396 return status;
1399 cache->width = width;
1400 cache->height = height;
1401 *out = cache;
1402 return CAIRO_STATUS_SUCCESS;
1405 static void
1406 _directfb_destroy_font_cache (cairo_directfb_font_cache_t *cache)
1408 cache->dfbsurface->Release (cache->dfbsurface);
1409 free (cache);
1412 static cairo_status_t
1413 _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
1414 cairo_scaled_font_t *scaled_font,
1415 const cairo_glyph_t *glyphs,
1416 int num_glyphs,
1417 cairo_directfb_font_cache_t **ret_cache,
1418 DFBRectangle *rects,
1419 DFBPoint *points,
1420 int *ret_num)
1422 cairo_status_t status;
1423 cairo_scaled_glyph_t *chars[num_glyphs];
1424 int num_chars = 0;
1425 cairo_directfb_font_cache_t *cache = NULL;
1426 int n = 0;
1427 int x = 0;
1428 int y = 0;
1429 int w = 8;
1430 int h = 8;
1431 int i;
1433 D_DEBUG_AT (CairoDFB_Font, "%s( %p [%d] )\n", __FUNCTION__, glyphs, num_glyphs );
1435 _cairo_cache_freeze (scaled_font->glyphs);
1437 if (scaled_font->surface_private) {
1438 cache = scaled_font->surface_private;
1439 x = cache->x;
1440 y = cache->y;
1443 for (i = 0; i < num_glyphs; i++) {
1444 cairo_scaled_glyph_t *scaled_glyph;
1445 cairo_image_surface_t *img;
1447 D_DEBUG_AT (CairoDFB_Font, " -> [%2d] = %4lu\n", i, glyphs[i].index );
1449 status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index,
1450 CAIRO_SCALED_GLYPH_INFO_SURFACE,
1451 &scaled_glyph);
1452 if (status) {
1453 _cairo_cache_thaw (scaled_font->glyphs);
1454 return status;
1457 img = scaled_glyph->surface;
1458 switch (img->format) {
1459 case CAIRO_FORMAT_A1:
1460 case CAIRO_FORMAT_A8:
1461 case CAIRO_FORMAT_ARGB32:
1462 break;
1463 default:
1464 D_DEBUG_AT (CairoDFB_Font,
1465 " -> Unsupported font format %d!\n", img->format);
1466 _cairo_cache_thaw (scaled_font->glyphs);
1467 return CAIRO_INT_STATUS_UNSUPPORTED;
1470 points[n].x = _cairo_lround (glyphs[i].x - img->base.device_transform.x0);
1471 points[n].y = _cairo_lround (glyphs[i].y - img->base.device_transform.y0);
1473 // D_DEBUG_AT (CairoDFB_Font, " (%4d,%4d) [%2d]\n", points[n].x, points[n].y, n );
1475 if (points[n].x >= surface->width ||
1476 points[n].y >= surface->height ||
1477 points[n].x+img->width <= 0 ||
1478 points[n].y+img->height <= 0)
1480 continue;
1483 if (scaled_glyph->surface_private == NULL) {
1484 DFBRectangle *rect;
1486 if (x+img->width > 2048) {
1487 x = 0;
1488 y = h;
1489 h = 0;
1492 rects[n].x = x;
1493 rects[n].y = y;
1494 rects[n].w = img->width;
1495 rects[n].h = img->height;
1497 x += img->width;
1498 h = MAX (h, img->height);
1499 w = MAX (w, x);
1501 /* Remember glyph location */
1502 rect = malloc (sizeof (DFBRectangle));
1503 if (rect == NULL) {
1504 _cairo_cache_thaw (scaled_font->glyphs);
1505 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1507 *rect = rects[n];
1509 scaled_glyph->surface_private = rect;
1510 chars[num_chars++] = scaled_glyph;
1512 D_DEBUG_AT (CairoDFB_Font, " -> loading at %4d,%2d <- rect %p, img %p, entry %p\n",
1513 rects[n].x, rects[n].y, rect, scaled_glyph->surface, scaled_glyph);
1514 } else {
1515 rects[n] = *(DFBRectangle *) scaled_glyph->surface_private;
1517 D_DEBUG_AT (CairoDFB_Font, " -> exists at %4d,%2d\n", rects[n].x, rects[n].y);
1520 n++;
1523 if (n == 0) {
1524 _cairo_cache_thaw (scaled_font->glyphs);
1525 return CAIRO_INT_STATUS_NOTHING_TO_DO;
1528 h += y;
1529 w = MAX (w, 8);
1530 h = MAX (h, 8);
1532 /* XXX query maximum surface size */
1533 if (w > 2048 || h > 2048) {
1534 _cairo_cache_thaw (scaled_font->glyphs);
1535 return CAIRO_INT_STATUS_UNSUPPORTED;
1538 if (cache) {
1539 if (cache->width < w || cache->height < h) {
1540 cairo_directfb_font_cache_t *new_cache;
1542 w = MAX (w, cache->width);
1543 h = MAX (h, cache->height);
1545 D_DEBUG_AT (CairoDFB_Font, " -> Reallocating font cache (%dx%d).\n", w, h);
1547 status = _directfb_allocate_font_cache (surface->dfb,
1548 w, h,
1549 &new_cache);
1550 if (status) {
1551 _cairo_cache_thaw (scaled_font->glyphs);
1552 return status;
1555 new_cache->dfbsurface->Blit (new_cache->dfbsurface,
1556 cache->dfbsurface, NULL, 0, 0);
1558 _directfb_destroy_font_cache (cache);
1559 scaled_font->surface_private = cache = new_cache;
1561 } else {
1562 D_DEBUG_AT (CairoDFB_Font, " -> Allocating font cache (%dx%d).\n", w, h);
1564 status = _directfb_allocate_font_cache (surface->dfb, w, h, &cache);
1565 if (status) {
1566 _cairo_cache_thaw (scaled_font->glyphs);
1567 return status;
1570 scaled_font->surface_backend = &_cairo_directfb_surface_backend;
1571 scaled_font->surface_private = cache;
1574 if (num_chars) {
1575 unsigned char *data;
1576 int pitch;
1578 if (cache->dfbsurface->Lock (cache->dfbsurface,
1579 DSLF_WRITE, (void *)&data, &pitch))
1581 _cairo_cache_thaw (scaled_font->glyphs);
1582 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1585 D_DEBUG_AT (CairoDFB_Font, " => %d chars to load, cache %dx%d\n", num_chars, cache->width, cache->height);
1587 for (i = 0; i < num_chars; i++) {
1588 cairo_image_surface_t *img = chars[i]->surface;
1589 DFBRectangle *rect = chars[i]->surface_private;
1590 unsigned char *dst = data;
1591 unsigned char *src;
1592 int j;
1594 D_DEBUG_AT (CairoDFB_Font, " -> loading [%2d] <- rect %p, img %p, entry %p\n", i, rect, img, chars[i]);
1596 src = img->data;
1598 D_DEBUG_AT (CairoDFB_Font, " from %p\n", src);
1600 dst += rect->y * pitch + (_directfb_argb_font ? (rect->x<<2) : rect->x);
1602 D_DEBUG_AT (CairoDFB_Font, " to %4d,%2d (%p)\n", rect->x, rect->y, dst);
1604 if (img->format == CAIRO_FORMAT_A1) {
1605 for (h = rect->h; h; h--) {
1606 if (_directfb_argb_font) {
1607 for (j = 0; j < rect->w; j++)
1608 ((uint32_t *) dst)[j] = (src[j>>3] & (1 << (j&7))) ? 0xffffffff : 0;
1609 } else {
1610 for (j = 0; j < rect->w; j++)
1611 dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0;
1614 dst += pitch;
1615 src += img->stride;
1617 } else if (img->format == CAIRO_FORMAT_A8) {
1618 for (h = rect->h; h; h--) {
1619 if (_directfb_argb_font) {
1620 for (j = 0; j < rect->w; j++)
1621 ((uint32_t *) dst)[j] = src[j] * 0x01010101;
1622 } else {
1623 direct_memcpy (dst, src, rect->w);
1626 dst += pitch;
1627 src += img->stride;
1629 } else { /* ARGB32 */
1630 for (h = rect->h; h; h--) {
1631 if (_directfb_argb_font) {
1632 direct_memcpy (dst, src, rect->w<<2);
1633 } else {
1634 for (j = 0; j < rect->w; j++)
1635 dst[j] = ((uint32_t *) src)[j] >> 24;
1638 dst += pitch;
1639 src += img->stride;
1644 cache->dfbsurface->Unlock (cache->dfbsurface);
1647 _cairo_cache_thaw (scaled_font->glyphs);
1649 cache->x = x;
1650 cache->y = y;
1652 D_DEBUG_AT (CairoDFB_Font, " => cache %d,%d, %p [%d]\n", x, y, cache, n);
1654 *ret_cache = cache;
1655 *ret_num = n;
1657 return CAIRO_STATUS_SUCCESS;
1660 static void
1661 _cairo_directfb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
1663 cairo_directfb_font_cache_t *cache = scaled_font->surface_private;
1665 D_DEBUG_AT (CairoDFB_Font,
1666 "%s( scaled_font=%p ).\n", __FUNCTION__, scaled_font);
1668 if (cache != NULL) {
1669 _directfb_destroy_font_cache (cache);
1670 scaled_font->surface_private = NULL;
1674 static void
1675 _cairo_directfb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
1676 cairo_scaled_font_t *scaled_font)
1678 D_DEBUG_AT (CairoDFB_Font,
1679 "%s( scaled_glyph=%p, scaled_font=%p ).\n",
1680 __FUNCTION__, scaled_glyph, scaled_font);
1682 if (scaled_glyph->surface_private != NULL) {
1683 free (scaled_glyph->surface_private);
1684 scaled_glyph->surface_private = NULL;
1688 static cairo_int_status_t
1689 _cairo_directfb_surface_show_glyphs (void *abstract_dst,
1690 cairo_operator_t op,
1691 cairo_pattern_t *pattern,
1692 cairo_glyph_t *glyphs,
1693 int num_glyphs,
1694 cairo_scaled_font_t *scaled_font,
1695 int *remaining_glyphs)
1697 cairo_directfb_surface_t *dst = abstract_dst;
1698 cairo_directfb_font_cache_t *cache;
1699 cairo_status_t status;
1700 DFBSurfaceBlittingFlags flags;
1701 DFBSurfaceBlendFunction sblend;
1702 DFBSurfaceBlendFunction dblend;
1703 DFBRectangle rects[num_glyphs];
1704 DFBPoint points[num_glyphs];
1705 int num;
1706 const cairo_color_t *color;
1709 D_DEBUG_AT (CairoDFB_Font,
1710 "%s( dst=%p, op=%d, pattern=%p, glyphs=%p, num_glyphs=%d, scaled_font=%p ).\n",
1711 __FUNCTION__, dst, op, pattern, glyphs, num_glyphs, scaled_font);
1713 if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
1714 return CAIRO_INT_STATUS_UNSUPPORTED;
1716 /* Fallback if we need to emulate clip regions */
1717 if (dst->base.clip &&
1718 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
1719 dst->base.clip->surface != NULL))
1721 return CAIRO_INT_STATUS_UNSUPPORTED;
1724 /* XXX Unbounded operators are not handled correctly */
1725 if (! _cairo_operator_bounded_by_mask (op))
1726 return CAIRO_INT_STATUS_UNSUPPORTED;
1727 if (! _cairo_operator_bounded_by_source (op))
1728 return CAIRO_INT_STATUS_UNSUPPORTED;
1730 if (! _directfb_get_operator (op, &sblend, &dblend) ||
1731 sblend == DSBF_DESTALPHA || sblend == DSBF_INVDESTALPHA)
1733 return CAIRO_INT_STATUS_UNSUPPORTED;
1736 status = _directfb_acquire_font_cache (dst, scaled_font, glyphs, num_glyphs,
1737 &cache, &rects[0], &points[0], &num);
1738 if (status) {
1739 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
1740 status = CAIRO_STATUS_SUCCESS;
1741 return status;
1744 color = &((cairo_solid_pattern_t *) pattern)->color;
1746 flags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE;
1747 if (! CAIRO_COLOR_IS_OPAQUE (color))
1748 flags |= DSBLIT_BLEND_COLORALPHA;
1750 if (!_directfb_argb_font) {
1751 if (sblend == DSBF_ONE) {
1752 sblend = DSBF_SRCALPHA;
1753 if (dblend == DSBF_ZERO)
1754 dblend = DSBF_INVSRCALPHA;
1758 dst->dfbsurface->SetBlittingFlags (dst->dfbsurface, flags);
1759 dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
1760 dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
1761 if (dst->blit_premultiplied) {
1762 dst->dfbsurface->SetColor (dst->dfbsurface,
1763 color->red_short >> 8,
1764 color->green_short >> 8,
1765 color->blue_short >> 8,
1766 color->alpha_short >> 8);
1767 } else {
1768 dst->dfbsurface->SetColor (dst->dfbsurface,
1769 color->red * 0xff,
1770 color->green * 0xff,
1771 color->blue * 0xff,
1772 color->alpha * 0xff);
1775 D_DEBUG_AT (CairoDFB_Font, "Running BatchBlit().\n");
1777 RUN_CLIPPED (dst, NULL,
1778 dst->dfbsurface->BatchBlit (dst->dfbsurface,
1779 cache->dfbsurface, rects, points, num));
1781 return CAIRO_STATUS_SUCCESS;
1783 #endif /* DFB_SHOW_GLYPHS */
1786 static cairo_bool_t
1787 _cairo_directfb_surface_is_similar (void *surface_a, void *surface_b, cairo_content_t content)
1789 cairo_directfb_surface_t *a = (cairo_directfb_surface_t *) surface_a;
1790 cairo_directfb_surface_t *b = (cairo_directfb_surface_t *) surface_b;
1792 return a->dfb == b->dfb;
1795 static cairo_surface_backend_t
1796 _cairo_directfb_surface_backend = {
1797 CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/
1798 _cairo_directfb_surface_create_similar,/*create_similar*/
1799 _cairo_directfb_surface_finish, /*finish*/
1800 _cairo_directfb_surface_acquire_source_image,/*acquire_source_image*/
1801 _cairo_directfb_surface_release_source_image,/*release_source_image*/
1802 _cairo_directfb_surface_acquire_dest_image,/*acquire_dest_image*/
1803 _cairo_directfb_surface_release_dest_image,/*release_dest_image*/
1804 _cairo_directfb_surface_clone_similar,/*clone_similar*/
1805 #if DFB_COMPOSITE
1806 _cairo_directfb_surface_composite,/*composite*/
1807 #else
1808 NULL,/*composite*/
1809 #endif
1810 #if DFB_RECTANGLES
1811 _cairo_directfb_surface_fill_rectangles,/*fill_rectangles*/
1812 #else
1813 NULL,/*fill_rectangles*/
1814 #endif
1815 #if DFB_COMPOSITE_TRAPEZOIDS
1816 _cairo_directfb_surface_composite_trapezoids,/*composite_trapezoids*/
1817 #else
1818 NULL,/*composite_trapezoids*/
1819 #endif
1820 NULL, /* copy_page */
1821 NULL, /* show_page */
1822 _cairo_directfb_surface_set_clip_region,/* set_clip_region */
1823 NULL, /* intersect_clip_path */
1824 _cairo_directfb_abstract_surface_get_extents,/* get_extents */
1825 NULL, /* old_show_glyphs */
1826 NULL, /* get_font_options */
1827 NULL, /* flush */
1828 NULL, /* mark_dirty_rectangle */
1829 #if DFB_SHOW_GLYPHS
1830 _cairo_directfb_surface_scaled_font_fini,/* scaled_font_fini */
1831 _cairo_directfb_surface_scaled_glyph_fini,/* scaled_glyph_fini */
1832 #else
1833 NULL,
1834 NULL,
1835 #endif
1836 NULL, /* paint */
1837 NULL, /* mask */
1838 NULL, /* stroke */
1839 NULL, /* fill */
1840 #if DFB_SHOW_GLYPHS
1841 _cairo_directfb_surface_show_glyphs,/* show_glyphs */
1842 #else
1843 NULL, /* show_glyphs */
1844 #endif
1845 NULL, /* snapshot */
1846 _cairo_directfb_surface_is_similar,
1847 NULL /* reset */
1851 static void
1852 cairo_directfb_surface_backend_init (IDirectFB *dfb)
1854 static int done = 0;
1856 if (done)
1857 return;
1859 if (getenv ("CAIRO_DIRECTFB_NO_ACCEL")) {
1860 #if DFB_RECTANGLES
1861 _cairo_directfb_surface_backend.fill_rectangles = NULL;
1862 #endif
1863 #if DFB_COMPOSITE
1864 _cairo_directfb_surface_backend.composite = NULL;
1865 #endif
1866 #if DFB_COMPOSITE_TRAPEZOIDS
1867 _cairo_directfb_surface_backend.composite_trapezoids = NULL;
1868 #endif
1869 #if DFB_SHOW_GLYPHS
1870 _cairo_directfb_surface_backend.scaled_font_fini = NULL;
1871 _cairo_directfb_surface_backend.scaled_glyph_fini = NULL;
1872 _cairo_directfb_surface_backend.show_glyphs = NULL;
1873 #endif
1874 D_DEBUG_AT (CairoDFB_Surface, "Acceleration disabled.\n");
1875 } else {
1876 DFBGraphicsDeviceDescription dsc;
1878 dfb->GetDeviceDescription (dfb, &dsc);
1880 #if DFB_COMPOSITE
1881 // if (!(dsc.acceleration_mask & DFXL_BLIT))
1882 // _cairo_directfb_surface_backend.composite = NULL;
1883 #endif
1885 #if DFB_COMPOSITE_TRAPEZOIDS
1886 // if (!(dsc.acceleration_mask & DFXL_TEXTRIANGLES))
1887 // _cairo_directfb_surface_backend.composite_trapezoids = NULL;
1888 #endif
1891 if (getenv ("CAIRO_DIRECTFB_ARGB_FONT")) {
1892 _directfb_argb_font = 1;
1893 D_DEBUG_AT (CairoDFB_Surface, "Using ARGB fonts.\n");
1896 done = 1;
1899 cairo_surface_t *
1900 cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
1902 cairo_directfb_surface_t *surface;
1903 DFBSurfacePixelFormat format;
1904 DFBSurfaceCapabilities caps;
1906 D_ASSERT (dfb != NULL);
1907 D_ASSERT (dfbsurface != NULL);
1909 cairo_directfb_surface_backend_init (dfb);
1911 surface = calloc (1, sizeof (cairo_directfb_surface_t));
1912 if (surface == NULL)
1913 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1915 dfbsurface->AddRef (dfbsurface);
1916 dfbsurface->GetPixelFormat (dfbsurface, &format);
1917 dfbsurface->GetSize (dfbsurface, &surface->width, &surface->height);
1918 surface->dfb = dfb;
1919 surface->dfbsurface = dfbsurface;
1920 surface->format = _directfb_to_cairo_format (format);
1921 surface->content = _directfb_format_to_content (format);
1923 dfbsurface->GetCapabilities (dfbsurface, &caps);
1924 if (caps & DSCAPS_PREMULTIPLIED)
1925 surface->blit_premultiplied = TRUE;
1927 _cairo_surface_init (&surface->base,
1928 &_cairo_directfb_surface_backend,
1929 surface->content);
1931 return &surface->base;