Add stubs for Direct3D9 backend.
[cairo/gpu.git] / src / cairo-directfb-surface.c
blob174711757f3be1e4b6c0893983e92816b3100054
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 (unlikely (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 cairo_directfb_surface_t *surface = abstract_surface;
553 IDirectFBSurface *buffer = image_extra;
555 D_DEBUG_AT (CairoDFB_Acquire,
556 "%s( surface=%p ).\n", __FUNCTION__, surface);
558 buffer->Unlock (buffer);
560 cairo_surface_destroy (&image->base);
563 static cairo_status_t
564 _cairo_directfb_surface_acquire_dest_image (void *abstract_surface,
565 cairo_rectangle_int_t *interest_rect,
566 cairo_image_surface_t **image_out,
567 cairo_rectangle_int_t *image_rect_out,
568 void **image_extra)
570 cairo_directfb_surface_t *surface = abstract_surface;
572 D_DEBUG_AT (CairoDFB_Acquire,
573 "%s( surface=%p (%dx%d), interest_rect={ %u %u %u %u } ).\n",
574 __FUNCTION__, surface, surface->width, surface->height,
575 interest_rect ? interest_rect->x : 0,
576 interest_rect ? interest_rect->y : 0,
577 interest_rect ? interest_rect->width : (unsigned) surface->width,
578 interest_rect ? interest_rect->height : (unsigned) surface->height);
580 return _directfb_acquire_surface (surface, interest_rect, image_out,
581 image_rect_out, image_extra,
582 DSLF_READ | DSLF_WRITE);
585 static void
586 _cairo_directfb_surface_release_dest_image (void *abstract_surface,
587 cairo_rectangle_int_t *interest_rect,
588 cairo_image_surface_t *image,
589 cairo_rectangle_int_t *image_rect,
590 void *image_extra)
592 cairo_directfb_surface_t *surface = abstract_surface;
593 IDirectFBSurface *buffer = image_extra;
595 D_DEBUG_AT (CairoDFB_Acquire,
596 "%s( surface=%p ).\n", __FUNCTION__, surface);
598 buffer->Unlock (buffer);
600 if (surface->dfbsurface != buffer) {
601 DFBRegion region = {
602 .x1 = interest_rect->x,
603 .y1 = interest_rect->y,
604 .x2 = interest_rect->x + interest_rect->width - 1,
605 .y2 = interest_rect->y + interest_rect->height - 1
607 surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, DSBLIT_NOFX);
608 RUN_CLIPPED (surface, &region,
609 surface->dfbsurface->Blit (surface->dfbsurface,
610 buffer, NULL,
611 image_rect->x, image_rect->y));
614 cairo_surface_destroy (&image->base);
617 static cairo_status_t
618 _cairo_directfb_surface_clone_similar (void *abstract_surface,
619 cairo_surface_t *src,
620 cairo_content_t content,
621 int src_x,
622 int src_y,
623 int width,
624 int height,
625 int *clone_offset_x,
626 int *clone_offset_y,
627 cairo_surface_t **clone_out)
629 cairo_directfb_surface_t *surface = abstract_surface;
630 cairo_directfb_surface_t *clone;
632 D_DEBUG_AT (CairoDFB_Surface,
633 "%s( surface=%p, src=%p ).\n", __FUNCTION__, surface, src);
635 if (src->backend == surface->base.backend) {
636 *clone_offset_x = 0;
637 *clone_offset_y = 0;
638 *clone_out = cairo_surface_reference (src);
640 return CAIRO_STATUS_SUCCESS;
641 } else if (_cairo_surface_is_image (src)) {
642 cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
643 unsigned char *dst, *src = image_src->data;
644 int pitch;
645 int i, j;
646 DFBResult ret;
648 clone = (cairo_directfb_surface_t *)
649 _cairo_directfb_surface_create_similar (surface,
650 _cairo_content_from_format (image_src->format),
651 width, height);
652 if (clone == NULL)
653 return CAIRO_INT_STATUS_UNSUPPORTED;
654 if (clone->base.status)
655 return clone->base.status;
657 ret = clone->dfbsurface->Lock (clone->dfbsurface,
658 DSLF_WRITE, (void *)&dst, &pitch);
659 if (ret) {
660 DirectFBError ("IDirectFBSurface::Lock()", ret);
661 cairo_surface_destroy (&clone->base);
662 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
665 src += image_src->stride * src_y;
666 if (image_src->format == CAIRO_FORMAT_A1) {
667 /* A1 -> A8 */
668 dst -= src_x;
669 for (i = 0; i < height; i++) {
670 for (j = src_x; j < src_x + width; j++)
671 dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00;
672 dst += pitch;
673 src += image_src->stride;
675 } else {
676 int len;
678 if (image_src->format == CAIRO_FORMAT_A8) {
679 src += src_x;
680 len = width;
681 } else {
682 src += src_x * 4;
683 len = width * 4;
686 for (i = 0; i < height; i++) {
687 direct_memcpy (dst, src, len);
688 dst += pitch;
689 src += image_src->stride;
693 clone->dfbsurface->Unlock (clone->dfbsurface);
695 *clone_offset_x = src_x;
696 *clone_offset_y = src_y;
697 *clone_out = &clone->base;
698 return CAIRO_STATUS_SUCCESS;
701 return CAIRO_INT_STATUS_UNSUPPORTED;
704 #if DFB_COMPOSITE || DFB_COMPOSITE_TRAPEZOIDS
705 static cairo_int_status_t
706 _directfb_prepare_composite (cairo_directfb_surface_t *dst,
707 const cairo_pattern_t *src_pattern,
708 const cairo_pattern_t *mask_pattern,
709 cairo_operator_t op,
710 int *src_x, int *src_y,
711 int *mask_x, int *mask_y,
712 unsigned int width,
713 unsigned int height,
714 cairo_directfb_surface_t **ret_src,
715 cairo_surface_attributes_t *ret_src_attr)
717 cairo_directfb_surface_t *src;
718 cairo_surface_attributes_t src_attr;
719 cairo_status_t status;
720 DFBSurfaceBlittingFlags flags;
721 DFBSurfaceBlendFunction sblend;
722 DFBSurfaceBlendFunction dblend;
723 const cairo_color_t *color;
725 /* XXX Unbounded operators are not handled correctly */
726 if (! _cairo_operator_bounded_by_source (op))
727 return CAIRO_INT_STATUS_UNSUPPORTED;
729 if (! _directfb_get_operator (op, &sblend, &dblend))
730 return CAIRO_INT_STATUS_UNSUPPORTED;
732 if (mask_pattern) {
733 cairo_solid_pattern_t *pattern;
735 return CAIRO_INT_STATUS_UNSUPPORTED;
736 if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
737 const cairo_pattern_t *tmp;
738 int tmp_x, tmp_y;
740 if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID ||
741 sblend == DSBF_INVDESTALPHA) /* Doesn't work correctly */
742 return CAIRO_INT_STATUS_UNSUPPORTED;
744 D_DEBUG_AT (CairoDFB_Render, "Replacing src pattern by mask pattern.\n");
746 tmp = src_pattern;
747 tmp_x = *src_x; tmp_y = *src_y;
749 src_pattern = mask_pattern;
750 *src_x = *mask_x; *src_y = *mask_y;
752 mask_pattern = tmp;
753 *mask_x = tmp_x; *mask_y = tmp_y;
755 if (sblend == DSBF_ONE) {
756 sblend = DSBF_SRCALPHA;
757 /*dblend = DSBF_INVSRCALPHA;*/
761 color = &((cairo_solid_pattern_t *) mask_pattern)->color;
762 } else {
763 color = _cairo_stock_color (CAIRO_STOCK_WHITE);
766 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
767 CAIRO_CONTENT_COLOR_ALPHA,
768 *src_x, *src_y, width, height,
769 CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
770 (cairo_surface_t **) &src,
771 &src_attr);
772 if (status)
773 return status;
775 if (src->base.backend != &_cairo_directfb_surface_backend ||
776 src->dfb != dst->dfb)
778 _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
779 return CAIRO_INT_STATUS_UNSUPPORTED;
782 if (src->content == CAIRO_CONTENT_COLOR) {
783 if (sblend == DSBF_SRCALPHA)
784 sblend = DSBF_ONE;
785 else if (sblend == DSBF_INVSRCALPHA)
786 sblend = DSBF_ZERO;
788 if (dblend == DSBF_SRCALPHA)
789 dblend = DSBF_ONE;
790 else if (dblend == DSBF_INVSRCALPHA)
791 dblend = DSBF_ZERO;
794 if (dst->content == CAIRO_CONTENT_COLOR) {
795 if (sblend == DSBF_DESTALPHA)
796 sblend = DSBF_ONE;
797 else if (sblend == DSBF_INVDESTALPHA)
798 sblend = DSBF_ZERO;
800 if (dblend == DSBF_DESTALPHA)
801 dblend = DSBF_ONE;
802 else if (dblend == DSBF_INVDESTALPHA)
803 dblend = DSBF_ZERO;
806 flags = (sblend == DSBF_ONE && dblend == DSBF_ZERO)
807 ? DSBLIT_NOFX : DSBLIT_BLEND_ALPHACHANNEL;
808 if (! CAIRO_COLOR_IS_OPAQUE (color))
809 flags |= DSBLIT_BLEND_COLORALPHA;
810 if (! _cairo_color_equal (color, _cairo_stock_color (CAIRO_STOCK_WHITE)))
811 flags |= DSBLIT_COLORIZE;
813 dst->dfbsurface->SetBlittingFlags (dst->dfbsurface, flags);
815 if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) {
816 dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
817 dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
820 if (flags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_COLORIZE)) {
821 if (dst->blit_premultiplied) {
822 dst->dfbsurface->SetColor (dst->dfbsurface,
823 color->red_short >> 8,
824 color->green_short >> 8,
825 color->blue_short >> 8,
826 color->alpha_short >> 8);
827 } else {
828 dst->dfbsurface->SetColor (dst->dfbsurface,
829 color->red * 0xff,
830 color->green * 0xff,
831 color->blue * 0xff,
832 color->alpha * 0xff);
836 *ret_src = src;
837 *ret_src_attr = src_attr;
839 return CAIRO_STATUS_SUCCESS;
842 static void
843 _directfb_finish_composite (cairo_directfb_surface_t *dst,
844 const cairo_pattern_t *src_pattern,
845 cairo_surface_t *src,
846 cairo_surface_attributes_t *src_attr)
848 _cairo_pattern_release_surface (src_pattern, src, src_attr);
850 #endif /* DFB_COMPOSITE || DFB_COMPOSITE_TRAPEZOIDS */
852 #if DFB_COMPOSITE
853 static DFBAccelerationMask
854 _directfb_categorize_operation (cairo_surface_attributes_t *src_attr)
856 cairo_matrix_t *m = &src_attr->matrix;
858 if (m->xy != 0 || m->yx != 0 || m->xx < 0 || m->yy < 0) {
859 if (src_attr->extend != CAIRO_EXTEND_NONE)
860 return DFXL_NONE;
862 return DFXL_TEXTRIANGLES;
865 if (m->xx != 1 || m->yy != 1) {
866 if (src_attr->extend != CAIRO_EXTEND_NONE)
867 return DFXL_NONE;
869 return DFXL_STRETCHBLIT;
872 switch (src_attr->extend) {
873 case CAIRO_EXTEND_NONE:
874 case CAIRO_EXTEND_REPEAT:
875 if (_cairo_matrix_is_integer_translation (&src_attr->matrix,
876 NULL, NULL))
878 return DFXL_BLIT;
880 else
882 return DFXL_STRETCHBLIT;
885 default:
886 case CAIRO_EXTEND_REFLECT:
887 case CAIRO_EXTEND_PAD:
888 return DFXL_NONE;
892 static cairo_int_status_t
893 _cairo_directfb_surface_composite (cairo_operator_t op,
894 const cairo_pattern_t *src_pattern,
895 const cairo_pattern_t *mask_pattern,
896 void *abstract_dst,
897 int src_x, int src_y,
898 int mask_x, int mask_y,
899 int dst_x, int dst_y,
900 unsigned int width,
901 unsigned int height)
903 cairo_directfb_surface_t *dst = abstract_dst;
904 cairo_directfb_surface_t *src;
905 cairo_surface_attributes_t src_attr;
906 cairo_bool_t is_integer_translation;
907 DFBAccelerationMask accel, mask;
908 cairo_int_status_t status;
909 int tx, ty;
911 D_DEBUG_AT (CairoDFB_Render,
912 "%s( op=%d, src_pattern=%p, mask_pattern=%p, dst=%p,"
913 " src_x=%d, src_y=%d, mask_x=%d, mask_y=%d, dst_x=%d,"
914 " dst_y=%d, width=%u, height=%u ).\n",
915 __FUNCTION__, op, src_pattern, mask_pattern, dst,
916 src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
918 status = _directfb_prepare_composite (dst, src_pattern, mask_pattern, op,
919 &src_x, &src_y, &mask_x, &mask_y,
920 width, height, &src, &src_attr);
921 if (status)
922 return status;
924 accel = _directfb_categorize_operation (&src_attr);
925 if (accel == DFXL_NONE) {
926 _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
927 return CAIRO_INT_STATUS_UNSUPPORTED;
930 dst->dfbsurface->GetAccelerationMask (dst->dfbsurface,
931 src->dfbsurface,
932 &mask);
933 if ((mask & accel) == 0) {
934 D_DEBUG_AT (CairoDFB_Render, "No acceleration (%08x)!\n", accel);
935 if (accel != DFXL_BLIT) {
936 _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
937 return CAIRO_INT_STATUS_UNSUPPORTED;
941 src_x += src_attr.x_offset;
942 src_y += src_attr.y_offset;
944 switch (accel) {
945 case DFXL_BLIT:
947 DFBRectangle sr;
949 is_integer_translation =
950 _cairo_matrix_is_integer_translation (&src_attr.matrix,
951 &tx, &ty);
952 assert (is_integer_translation);
954 sr.x = src_x + tx;
955 sr.y = src_y + ty;
956 sr.w = width;
957 sr.h = height;
959 if (src_attr.extend == CAIRO_EXTEND_NONE) {
960 D_DEBUG_AT (CairoDFB_Render, "Running Blit().\n");
962 RUN_CLIPPED (dst, NULL,
963 dst->dfbsurface->Blit (dst->dfbsurface,
964 src->dfbsurface,
965 &sr,
966 dst_x, dst_y));
967 } else if (src_attr.extend == CAIRO_EXTEND_REPEAT) {
968 DFBRegion clip;
970 clip.x1 = dst_x;
971 clip.y1 = dst_y;
972 clip.x2 = dst_x + width - 1;
973 clip.y2 = dst_y + height - 1;
975 D_DEBUG_AT (CairoDFB_Render, "Running TileBlit().\n");
977 RUN_CLIPPED (dst, &clip,
978 dst->dfbsurface->TileBlit (dst->dfbsurface,
979 src->dfbsurface,
980 &sr,
981 dst_x, dst_y));
983 break;
986 case DFXL_STRETCHBLIT:
988 DFBRectangle sr, dr;
989 double x1, y1, x2, y2;
991 TRANSFORM_POINT2X (src_attr.matrix,
992 src_x, src_y, x1, y1);
993 TRANSFORM_POINT2X (src_attr.matrix,
994 src_x+width, src_y+height, x2, y2);
996 sr.x = floor (x1);
997 sr.y = floor (y1);
998 sr.w = ceil (x2) - sr.x;
999 sr.h = ceil (y2) - sr.y;
1001 dr.x = dst_x;
1002 dr.y = dst_y;
1003 dr.w = width;
1004 dr.h = height;
1006 D_DEBUG_AT (CairoDFB_Render, "Running StretchBlit().\n");
1008 RUN_CLIPPED (dst, NULL,
1009 dst->dfbsurface->StretchBlit (dst->dfbsurface,
1010 src->dfbsurface, &sr, &dr));
1011 break;
1014 case DFXL_TEXTRIANGLES:
1016 DFBRegion clip;
1017 DFBVertex v[4];
1018 float x1, y1, x2, y2;
1019 int w, h;
1021 status = cairo_matrix_invert (&src_attr.matrix);
1022 /* guaranteed by cairo_pattern_set_matrix (); */
1023 assert (status == CAIRO_STATUS_SUCCESS);
1025 x1 = src_x;
1026 y1 = src_y;
1027 x2 = width + x1;
1028 y2 = height + y1;
1030 src->dfbsurface->GetSize (src->dfbsurface, &w, &h);
1032 TRANSFORM_POINT3X (src_attr.matrix,
1033 x1, y1, v[0].x, v[0].y);
1034 v[0].z = 0;
1035 v[0].w = 1;
1036 v[0].s = x1 / w;
1037 v[0].t = y1 / h;
1039 TRANSFORM_POINT3X (src_attr.matrix,
1040 x2, y1, v[1].x, v[1].y);
1041 v[1].z = 0;
1042 v[1].w = 1;
1043 v[1].s = x2 / w;
1044 v[1].t = y1 / h;
1046 TRANSFORM_POINT3X (src_attr.matrix,
1047 x2, y2, v[2].x, v[2].y);
1048 v[2].z = 0;
1049 v[2].w = 1;
1050 v[2].s = x2 / w;
1051 v[2].t = y2 / h;
1053 TRANSFORM_POINT3X (src_attr.matrix,
1054 x1, y2, v[3].x, v[3].y);
1055 v[3].z = 0;
1056 v[3].w = 1;
1057 v[3].s = x1 / w;
1058 v[3].t = y2 / h;
1060 clip.x1 = dst_x;
1061 clip.y1 = dst_y;
1062 clip.x2 = dst_x + width - 1;
1063 clip.y2 = dst_y + height - 1;
1065 D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
1067 RUN_CLIPPED (dst, &clip,
1068 dst->dfbsurface->TextureTriangles (dst->dfbsurface,
1069 src->dfbsurface, v, NULL, 4, DTTF_FAN));
1070 break;
1073 default:
1074 D_BUG ("Unexpected operation");
1075 break;
1078 _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
1080 return status;
1082 #endif /* DFB_COMPOSITE */
1084 #if DFB_RECTANGLES
1085 static cairo_int_status_t
1086 _cairo_directfb_surface_fill_rectangles (void *abstract_surface,
1087 cairo_operator_t op,
1088 const cairo_color_t *color,
1089 cairo_rectangle_int_t *rects,
1090 int n_rects)
1092 cairo_directfb_surface_t *dst = abstract_surface;
1093 DFBSurfaceDrawingFlags flags;
1094 DFBSurfaceBlendFunction sblend;
1095 DFBSurfaceBlendFunction dblend;
1096 DFBRectangle r[n_rects];
1097 int i;
1099 D_DEBUG_AT (CairoDFB_Render,
1100 "%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n",
1101 __FUNCTION__, dst, op, color, rects, n_rects);
1103 if (! _cairo_operator_bounded_by_source (op))
1104 return CAIRO_INT_STATUS_UNSUPPORTED;
1106 if (! _directfb_get_operator (op, &sblend, &dblend))
1107 return CAIRO_INT_STATUS_UNSUPPORTED;
1109 if (CAIRO_COLOR_IS_OPAQUE (color)) {
1110 if (sblend == DSBF_SRCALPHA)
1111 sblend = DSBF_ONE;
1112 else if (sblend == DSBF_INVSRCALPHA)
1113 sblend = DSBF_ZERO;
1115 if (dblend == DSBF_SRCALPHA)
1116 dblend = DSBF_ONE;
1117 else if (dblend == DSBF_INVSRCALPHA)
1118 dblend = DSBF_ZERO;
1120 if (dst->content == CAIRO_CONTENT_COLOR) {
1121 if (sblend == DSBF_DESTALPHA)
1122 sblend = DSBF_ONE;
1123 else if (sblend == DSBF_INVDESTALPHA)
1124 sblend = DSBF_ZERO;
1126 if (dblend == DSBF_DESTALPHA)
1127 dblend = DSBF_ONE;
1128 else if (dblend == DSBF_INVDESTALPHA)
1129 dblend = DSBF_ZERO;
1132 flags = (sblend == DSBF_ONE && dblend == DSBF_ZERO) ? DSDRAW_NOFX : DSDRAW_BLEND;
1133 dst->dfbsurface->SetDrawingFlags (dst->dfbsurface, flags);
1134 if (flags & DSDRAW_BLEND) {
1135 dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
1136 dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
1139 dst->dfbsurface->SetColor (dst->dfbsurface,
1140 color->red_short >> 8,
1141 color->green_short >> 8,
1142 color->blue_short >> 8,
1143 color->alpha_short >> 8);
1145 for (i = 0; i < n_rects; i++) {
1146 r[i].x = rects[i].x;
1147 r[i].y = rects[i].y;
1148 r[i].w = rects[i].width;
1149 r[i].h = rects[i].height;
1152 RUN_CLIPPED (dst, NULL,
1153 dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects));
1155 return CAIRO_STATUS_SUCCESS;
1157 #endif
1159 #if DFB_COMPOSITE_TRAPEZOIDS
1160 static cairo_int_status_t
1161 _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
1162 const cairo_pattern_t *pattern,
1163 void *abstract_dst,
1164 cairo_antialias_t antialias,
1165 int src_x, int src_y,
1166 int dst_x, int dst_y,
1167 unsigned int width,
1168 unsigned int height,
1169 cairo_trapezoid_t *traps,
1170 int num_traps)
1172 cairo_directfb_surface_t *dst = abstract_dst;
1173 cairo_directfb_surface_t *src;
1174 cairo_surface_attributes_t src_attr;
1175 cairo_status_t status;
1176 DFBAccelerationMask accel;
1178 D_DEBUG_AT (CairoDFB_Render,
1179 "%s( op=%d, pattern=%p, dst=%p, antialias=%d,"
1180 " src_x=%d, src_y=%d, dst_x=%d, dst_y=%d,"
1181 " width=%u, height=%u, traps=%p, num_traps=%d ).\n",
1182 __FUNCTION__, op, pattern, dst, antialias,
1183 src_x, src_y, dst_x, dst_y, width, height, traps, num_traps);
1185 if (antialias != CAIRO_ANTIALIAS_NONE)
1186 return CAIRO_INT_STATUS_UNSUPPORTED;
1188 /* Textures are not supported yet. */
1189 if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
1190 return CAIRO_INT_STATUS_UNSUPPORTED;
1192 status = _directfb_prepare_composite (dst, pattern, NULL, op,
1193 &src_x, &src_y, NULL, NULL,
1194 width, height, &src, &src_attr);
1195 if (status)
1196 return status;
1198 dst->dfbsurface->GetAccelerationMask (dst->dfbsurface,
1199 src->dfbsurface,
1200 &accel);
1202 status = CAIRO_INT_STATUS_UNSUPPORTED;
1204 if (accel & DFXL_TEXTRIANGLES) {
1205 DFBVertex vertex[6*num_traps];
1206 DFBVertex *v = &vertex[0];
1207 int n = 0;
1209 #define ADD_TRI_V(V, X, Y) do { \
1210 (V)->x = (X); (V)->y = (Y); (V)->w = 1; (V)->z = (V)->s = (V)->t = 0; \
1211 } while (0)
1212 #define ADD_TRI(id, x1, y1, x2, y2, x3, y3) do {\
1213 const int p = (id)*3;\
1214 ADD_TRI_V (v+p+0, x1, y1); \
1215 ADD_TRI_V (v+p+1, x2, y2); \
1216 ADD_TRI_V (v+p+2, x3, y3); \
1217 } while (0)
1218 while (num_traps--) {
1219 double lx1, ly1, lx2, ly2;
1220 double rx1, ry1, rx2, ry2;
1222 lx1 = _cairo_fixed_to_double (traps->left.p1.x);
1223 ly1 = _cairo_fixed_to_double (traps->left.p1.y);
1224 lx2 = _cairo_fixed_to_double (traps->left.p2.x);
1225 ly2 = _cairo_fixed_to_double (traps->left.p2.y);
1226 rx1 = _cairo_fixed_to_double (traps->right.p1.x);
1227 ry1 = _cairo_fixed_to_double (traps->right.p1.y);
1228 rx2 = _cairo_fixed_to_double (traps->right.p2.x);
1229 ry2 = _cairo_fixed_to_double (traps->right.p2.y);
1231 if (traps->left.p1.y < traps->top) {
1232 double y = _cairo_fixed_to_double (traps->top);
1233 if (lx2 != lx1)
1234 lx1 = (y - ly1) * (lx2 - lx1) / (ly2 - ly1) + lx1;
1235 ly1 = y;
1237 if (traps->left.p2.y > traps->bottom) {
1238 double y = _cairo_fixed_to_double (traps->bottom);
1239 if (lx2 != lx1)
1240 lx2 = (y - ly1) * (lx2 - lx1) / (ly2 - ly1) + lx1;
1241 ly2 = y;
1244 if (traps->right.p1.y < traps->top) {
1245 double y = _cairo_fixed_to_double (traps->top);
1246 if (rx2 != rx1)
1247 rx1 = (y - ry1) * (rx2 - rx1) / (ry2 - ry1) + rx1;
1248 ry1 = y;
1250 if (traps->right.p2.y > traps->bottom) {
1251 double y = _cairo_fixed_to_double (traps->bottom);
1252 if (rx2 != rx1)
1253 rx2 = (y - ry1) * (rx2 - rx1) / (ry2 - ry1) + rx1;
1254 ry2 = y;
1257 if (lx1 == rx1 && ly1 == ry1) {
1258 ADD_TRI (0, lx2, ly2, lx1, ly1, rx2, ry2);
1259 v += 3;
1260 n += 3;
1261 } else if (lx2 == rx2 && ly2 == ry2) {
1262 ADD_TRI (0, lx1, ly1, lx2, ly2, rx1, ry1);
1263 v += 3;
1264 n += 3;
1265 } else {
1266 ADD_TRI (0, lx1, ly1, rx1, ry1, lx2, ly2);
1267 ADD_TRI (1, lx2, ly2, rx1, ry1, rx2, ry2);
1268 v += 6;
1269 n += 6;
1272 traps++;
1274 #undef ADD_TRI
1275 #undef ADD_TRI_V
1277 D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
1279 RUN_CLIPPED (dst, NULL,
1280 dst->dfbsurface->TextureTriangles (dst->dfbsurface,
1281 src->dfbsurface,
1282 vertex, NULL, n,
1283 DTTF_LIST));
1285 status = CAIRO_STATUS_SUCCESS;
1288 _directfb_finish_composite (dst, pattern, &src->base, &src_attr);
1290 return status;
1292 #endif /* DFB_COMPOSITE_TRAPEZOIDS */
1294 static cairo_int_status_t
1295 _cairo_directfb_surface_set_clip_region (void *abstract_surface,
1296 cairo_region_t *region)
1298 cairo_directfb_surface_t *surface = abstract_surface;
1300 D_DEBUG_AT (CairoDFB_Clip,
1301 "%s( surface=%p, region=%p ).\n",
1302 __FUNCTION__, surface, region);
1304 if (region) {
1305 int n_rects;
1306 cairo_status_t status;
1307 int i;
1309 surface->has_clip = TRUE;
1311 n_rects = cairo_region_num_rectangles (region);
1313 if (n_rects == 0)
1314 return CAIRO_STATUS_SUCCESS;
1316 if (surface->n_clips != n_rects) {
1317 if (surface->clips)
1318 free (surface->clips);
1320 surface->clips = _cairo_malloc_ab (n_rects, sizeof (DFBRegion));
1321 if (!surface->clips) {
1322 surface->n_clips = 0;
1323 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1326 surface->n_clips = n_rects;
1329 for (i = 0; i < n_rects; i++) {
1330 cairo_rectangle_int_t rect;
1332 cairo_region_get_rectangle (region, i, &rect);
1334 surface->clips[i].x1 = rect.x;
1335 surface->clips[i].y1 = rect.y;
1336 surface->clips[i].x2 = rect.x + rect.width - 1;
1337 surface->clips[i].y2 = rect.y + rect.height - 1;
1339 } else {
1340 surface->has_clip = FALSE;
1341 if (surface->clips) {
1342 free (surface->clips);
1343 surface->clips = NULL;
1344 surface->n_clips = 0;
1348 return CAIRO_STATUS_SUCCESS;
1351 static cairo_int_status_t
1352 _cairo_directfb_abstract_surface_get_extents (void *abstract_surface,
1353 cairo_rectangle_int_t *rectangle)
1355 cairo_directfb_surface_t *surface = abstract_surface;
1357 D_DEBUG_AT (CairoDFB_Surface,
1358 "%s( surface=%p, rectangle=%p ).\n",
1359 __FUNCTION__, surface, rectangle);
1361 if (!surface->local) {
1362 surface->dfbsurface->GetSize (surface->dfbsurface,
1363 &surface->width, &surface->height);
1366 rectangle->x = 0;
1367 rectangle->y = 0;
1368 rectangle->width = surface->width;
1369 rectangle->height = surface->height;
1371 return CAIRO_STATUS_SUCCESS;
1374 #if DFB_SHOW_GLYPHS
1375 static cairo_status_t
1376 _directfb_allocate_font_cache (IDirectFB *dfb,
1377 int width, int height,
1378 cairo_directfb_font_cache_t **out)
1380 cairo_directfb_font_cache_t *cache;
1381 cairo_status_t status;
1383 cache = calloc (1, sizeof (cairo_directfb_font_cache_t));
1384 if (cache == NULL)
1385 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1387 cache->dfb = dfb;
1388 status = _directfb_buffer_surface_create (dfb,
1389 _directfb_argb_font ? DSPF_ARGB : DSPF_A8,
1390 width, height,
1391 &cache->dfbsurface);
1392 if (status) {
1393 free (cache);
1394 return status;
1397 cache->width = width;
1398 cache->height = height;
1399 *out = cache;
1400 return CAIRO_STATUS_SUCCESS;
1403 static void
1404 _directfb_destroy_font_cache (cairo_directfb_font_cache_t *cache)
1406 cache->dfbsurface->Release (cache->dfbsurface);
1407 free (cache);
1410 static cairo_status_t
1411 _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
1412 cairo_scaled_font_t *scaled_font,
1413 const cairo_glyph_t *glyphs,
1414 int num_glyphs,
1415 cairo_directfb_font_cache_t **ret_cache,
1416 DFBRectangle *rects,
1417 DFBPoint *points,
1418 int *ret_num)
1420 cairo_status_t status;
1421 cairo_scaled_glyph_t *chars[num_glyphs];
1422 int num_chars = 0;
1423 cairo_directfb_font_cache_t *cache = NULL;
1424 int n = 0;
1425 int x = 0;
1426 int y = 0;
1427 int w = 8;
1428 int h = 8;
1429 int i;
1431 D_DEBUG_AT (CairoDFB_Font, "%s( %p [%d] )\n", __FUNCTION__, glyphs, num_glyphs );
1433 _cairo_scaled_font_freeze_cache (scaled_font);
1435 if (scaled_font->surface_private) {
1436 cache = scaled_font->surface_private;
1437 x = cache->x;
1438 y = cache->y;
1441 for (i = 0; i < num_glyphs; i++) {
1442 cairo_scaled_glyph_t *scaled_glyph;
1443 cairo_image_surface_t *img;
1445 D_DEBUG_AT (CairoDFB_Font, " -> [%2d] = %4lu\n", i, glyphs[i].index );
1447 status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index,
1448 CAIRO_SCALED_GLYPH_INFO_SURFACE,
1449 &scaled_glyph);
1450 if (status) {
1451 _cairo_scaled_font_thaw_cache (scaled_font);
1452 return status;
1455 img = scaled_glyph->surface;
1456 switch (img->format) {
1457 case CAIRO_FORMAT_A1:
1458 case CAIRO_FORMAT_A8:
1459 case CAIRO_FORMAT_ARGB32:
1460 break;
1461 default:
1462 D_DEBUG_AT (CairoDFB_Font,
1463 " -> Unsupported font format %d!\n", img->format);
1464 _cairo_scaled_font_thaw_cache (scaled_font);
1465 return CAIRO_INT_STATUS_UNSUPPORTED;
1468 points[n].x = _cairo_lround (glyphs[i].x - img->base.device_transform.x0);
1469 points[n].y = _cairo_lround (glyphs[i].y - img->base.device_transform.y0);
1471 // D_DEBUG_AT (CairoDFB_Font, " (%4d,%4d) [%2d]\n", points[n].x, points[n].y, n );
1473 if (points[n].x >= surface->width ||
1474 points[n].y >= surface->height ||
1475 points[n].x+img->width <= 0 ||
1476 points[n].y+img->height <= 0)
1478 continue;
1481 if (scaled_glyph->surface_private == NULL) {
1482 DFBRectangle *rect;
1484 if (x+img->width > 2048) {
1485 x = 0;
1486 y = h;
1487 h = 0;
1490 rects[n].x = x;
1491 rects[n].y = y;
1492 rects[n].w = img->width;
1493 rects[n].h = img->height;
1495 x += img->width;
1496 h = MAX (h, img->height);
1497 w = MAX (w, x);
1499 /* Remember glyph location */
1500 rect = malloc (sizeof (DFBRectangle));
1501 if (rect == NULL) {
1502 _cairo_scaled_font_thaw_cache (scaled_font);
1503 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1505 *rect = rects[n];
1507 scaled_glyph->surface_private = rect;
1508 chars[num_chars++] = scaled_glyph;
1510 D_DEBUG_AT (CairoDFB_Font, " -> loading at %4d,%2d <- rect %p, img %p, entry %p\n",
1511 rects[n].x, rects[n].y, rect, scaled_glyph->surface, scaled_glyph);
1512 } else {
1513 rects[n] = *(DFBRectangle *) scaled_glyph->surface_private;
1515 D_DEBUG_AT (CairoDFB_Font, " -> exists at %4d,%2d\n", rects[n].x, rects[n].y);
1518 n++;
1521 if (n == 0) {
1522 _cairo_scaled_font_thaw_cache (scaled_font);
1523 return CAIRO_INT_STATUS_NOTHING_TO_DO;
1526 h += y;
1527 w = MAX (w, 8);
1528 h = MAX (h, 8);
1530 /* XXX query maximum surface size */
1531 if (w > 2048 || h > 2048) {
1532 _cairo_scaled_font_thaw_cache (scaled_font);
1533 return CAIRO_INT_STATUS_UNSUPPORTED;
1536 if (cache) {
1537 if (cache->width < w || cache->height < h) {
1538 cairo_directfb_font_cache_t *new_cache;
1540 w = MAX (w, cache->width);
1541 h = MAX (h, cache->height);
1543 D_DEBUG_AT (CairoDFB_Font, " -> Reallocating font cache (%dx%d).\n", w, h);
1545 status = _directfb_allocate_font_cache (surface->dfb,
1546 w, h,
1547 &new_cache);
1548 if (status) {
1549 _cairo_scaled_font_thaw_cache (scaled_font);
1550 return status;
1553 new_cache->dfbsurface->Blit (new_cache->dfbsurface,
1554 cache->dfbsurface, NULL, 0, 0);
1556 _directfb_destroy_font_cache (cache);
1557 scaled_font->surface_private = cache = new_cache;
1559 } else {
1560 D_DEBUG_AT (CairoDFB_Font, " -> Allocating font cache (%dx%d).\n", w, h);
1562 status = _directfb_allocate_font_cache (surface->dfb, w, h, &cache);
1563 if (status) {
1564 _cairo_scaled_font_thaw_cache (scaled_font);
1565 return status;
1568 scaled_font->surface_backend = &_cairo_directfb_surface_backend;
1569 scaled_font->surface_private = cache;
1572 if (num_chars) {
1573 unsigned char *data;
1574 int pitch;
1576 if (cache->dfbsurface->Lock (cache->dfbsurface,
1577 DSLF_WRITE, (void *)&data, &pitch))
1579 _cairo_scaled_font_thaw_cache (scaled_font);
1580 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1583 D_DEBUG_AT (CairoDFB_Font, " => %d chars to load, cache %dx%d\n", num_chars, cache->width, cache->height);
1585 for (i = 0; i < num_chars; i++) {
1586 cairo_image_surface_t *img = chars[i]->surface;
1587 DFBRectangle *rect = chars[i]->surface_private;
1588 unsigned char *dst = data;
1589 unsigned char *src;
1590 int j;
1592 D_DEBUG_AT (CairoDFB_Font, " -> loading [%2d] <- rect %p, img %p, entry %p\n", i, rect, img, chars[i]);
1594 src = img->data;
1596 D_DEBUG_AT (CairoDFB_Font, " from %p\n", src);
1598 dst += rect->y * pitch + (_directfb_argb_font ? (rect->x<<2) : rect->x);
1600 D_DEBUG_AT (CairoDFB_Font, " to %4d,%2d (%p)\n", rect->x, rect->y, dst);
1602 if (img->format == CAIRO_FORMAT_A1) {
1603 for (h = rect->h; h; h--) {
1604 if (_directfb_argb_font) {
1605 for (j = 0; j < rect->w; j++)
1606 ((uint32_t *) dst)[j] = (src[j>>3] & (1 << (j&7))) ? 0xffffffff : 0;
1607 } else {
1608 for (j = 0; j < rect->w; j++)
1609 dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0;
1612 dst += pitch;
1613 src += img->stride;
1615 } else if (img->format == CAIRO_FORMAT_A8) {
1616 for (h = rect->h; h; h--) {
1617 if (_directfb_argb_font) {
1618 for (j = 0; j < rect->w; j++)
1619 ((uint32_t *) dst)[j] = src[j] * 0x01010101;
1620 } else {
1621 direct_memcpy (dst, src, rect->w);
1624 dst += pitch;
1625 src += img->stride;
1627 } else { /* ARGB32 */
1628 for (h = rect->h; h; h--) {
1629 if (_directfb_argb_font) {
1630 direct_memcpy (dst, src, rect->w<<2);
1631 } else {
1632 for (j = 0; j < rect->w; j++)
1633 dst[j] = ((uint32_t *) src)[j] >> 24;
1636 dst += pitch;
1637 src += img->stride;
1642 cache->dfbsurface->Unlock (cache->dfbsurface);
1645 _cairo_scaled_font_thaw_cache (scaled_font);
1647 cache->x = x;
1648 cache->y = y;
1650 D_DEBUG_AT (CairoDFB_Font, " => cache %d,%d, %p [%d]\n", x, y, cache, n);
1652 *ret_cache = cache;
1653 *ret_num = n;
1655 return CAIRO_STATUS_SUCCESS;
1658 static void
1659 _cairo_directfb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
1661 cairo_directfb_font_cache_t *cache = scaled_font->surface_private;
1663 D_DEBUG_AT (CairoDFB_Font,
1664 "%s( scaled_font=%p ).\n", __FUNCTION__, scaled_font);
1666 if (cache != NULL) {
1667 _directfb_destroy_font_cache (cache);
1668 scaled_font->surface_private = NULL;
1672 static void
1673 _cairo_directfb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
1674 cairo_scaled_font_t *scaled_font)
1676 D_DEBUG_AT (CairoDFB_Font,
1677 "%s( scaled_glyph=%p, scaled_font=%p ).\n",
1678 __FUNCTION__, scaled_glyph, scaled_font);
1680 if (scaled_glyph->surface_private != NULL) {
1681 free (scaled_glyph->surface_private);
1682 scaled_glyph->surface_private = NULL;
1686 static cairo_int_status_t
1687 _cairo_directfb_surface_show_glyphs (void *abstract_dst,
1688 cairo_operator_t op,
1689 const cairo_pattern_t *pattern,
1690 cairo_glyph_t *glyphs,
1691 int num_glyphs,
1692 cairo_scaled_font_t *scaled_font,
1693 int *remaining_glyphs,
1694 cairo_rectangle_int_t *extents)
1696 cairo_directfb_surface_t *dst = abstract_dst;
1697 cairo_directfb_font_cache_t *cache;
1698 cairo_status_t status;
1699 DFBSurfaceBlittingFlags flags;
1700 DFBSurfaceBlendFunction sblend;
1701 DFBSurfaceBlendFunction dblend;
1702 DFBRectangle rects[num_glyphs];
1703 DFBPoint points[num_glyphs];
1704 int num;
1705 const cairo_color_t *color;
1708 D_DEBUG_AT (CairoDFB_Font,
1709 "%s( dst=%p, op=%d, pattern=%p, glyphs=%p, num_glyphs=%d, scaled_font=%p ).\n",
1710 __FUNCTION__, dst, op, pattern, glyphs, num_glyphs, scaled_font);
1712 if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
1713 return CAIRO_INT_STATUS_UNSUPPORTED;
1715 /* Fallback if we need to emulate clip regions */
1716 if (dst->base.clip &&
1717 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
1718 dst->base.clip->surface != NULL))
1720 return CAIRO_INT_STATUS_UNSUPPORTED;
1723 /* XXX Unbounded operators are not handled correctly */
1724 if (! _cairo_operator_bounded_by_mask (op))
1725 return CAIRO_INT_STATUS_UNSUPPORTED;
1726 if (! _cairo_operator_bounded_by_source (op))
1727 return CAIRO_INT_STATUS_UNSUPPORTED;
1729 if (! _directfb_get_operator (op, &sblend, &dblend) ||
1730 sblend == DSBF_DESTALPHA || sblend == DSBF_INVDESTALPHA)
1732 return CAIRO_INT_STATUS_UNSUPPORTED;
1735 status = _directfb_acquire_font_cache (dst, scaled_font, glyphs, num_glyphs,
1736 &cache, &rects[0], &points[0], &num);
1737 if (status) {
1738 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
1739 status = CAIRO_STATUS_SUCCESS;
1740 return status;
1743 color = &((cairo_solid_pattern_t *) pattern)->color;
1745 flags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE;
1746 if (! CAIRO_COLOR_IS_OPAQUE (color))
1747 flags |= DSBLIT_BLEND_COLORALPHA;
1749 if (!_directfb_argb_font) {
1750 if (sblend == DSBF_ONE) {
1751 sblend = DSBF_SRCALPHA;
1752 if (dblend == DSBF_ZERO)
1753 dblend = DSBF_INVSRCALPHA;
1757 dst->dfbsurface->SetBlittingFlags (dst->dfbsurface, flags);
1758 dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
1759 dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
1760 if (dst->blit_premultiplied) {
1761 dst->dfbsurface->SetColor (dst->dfbsurface,
1762 color->red_short >> 8,
1763 color->green_short >> 8,
1764 color->blue_short >> 8,
1765 color->alpha_short >> 8);
1766 } else {
1767 dst->dfbsurface->SetColor (dst->dfbsurface,
1768 color->red * 0xff,
1769 color->green * 0xff,
1770 color->blue * 0xff,
1771 color->alpha * 0xff);
1774 D_DEBUG_AT (CairoDFB_Font, "Running BatchBlit().\n");
1776 RUN_CLIPPED (dst, NULL,
1777 dst->dfbsurface->BatchBlit (dst->dfbsurface,
1778 cache->dfbsurface, rects, points, num));
1780 return CAIRO_STATUS_SUCCESS;
1782 #endif /* DFB_SHOW_GLYPHS */
1785 static cairo_bool_t
1786 _cairo_directfb_surface_is_similar (void *surface_a, void *surface_b, cairo_content_t content)
1788 cairo_directfb_surface_t *a = (cairo_directfb_surface_t *) surface_a;
1789 cairo_directfb_surface_t *b = (cairo_directfb_surface_t *) surface_b;
1791 return a->dfb == b->dfb;
1794 static cairo_surface_backend_t
1795 _cairo_directfb_surface_backend = {
1796 CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/
1797 _cairo_directfb_surface_create_similar,/*create_similar*/
1798 _cairo_directfb_surface_finish, /*finish*/
1799 _cairo_directfb_surface_acquire_source_image,/*acquire_source_image*/
1800 _cairo_directfb_surface_release_source_image,/*release_source_image*/
1801 _cairo_directfb_surface_acquire_dest_image,/*acquire_dest_image*/
1802 _cairo_directfb_surface_release_dest_image,/*release_dest_image*/
1803 _cairo_directfb_surface_clone_similar,/*clone_similar*/
1804 #if DFB_COMPOSITE
1805 _cairo_directfb_surface_composite,/*composite*/
1806 #else
1807 NULL,/*composite*/
1808 #endif
1809 #if DFB_RECTANGLES
1810 _cairo_directfb_surface_fill_rectangles,/*fill_rectangles*/
1811 #else
1812 NULL,/*fill_rectangles*/
1813 #endif
1814 #if DFB_COMPOSITE_TRAPEZOIDS
1815 _cairo_directfb_surface_composite_trapezoids,/*composite_trapezoids*/
1816 #else
1817 NULL,/*composite_trapezoids*/
1818 #endif
1819 NULL, /* create_span_renderer */
1820 NULL, /* check_span_renderer */
1821 NULL, /* copy_page */
1822 NULL, /* show_page */
1823 _cairo_directfb_surface_set_clip_region,/* set_clip_region */
1824 NULL, /* intersect_clip_path */
1825 _cairo_directfb_abstract_surface_get_extents,/* get_extents */
1826 NULL, /* old_show_glyphs */
1827 NULL, /* get_font_options */
1828 NULL, /* flush */
1829 NULL, /* mark_dirty_rectangle */
1830 #if DFB_SHOW_GLYPHS
1831 _cairo_directfb_surface_scaled_font_fini,/* scaled_font_fini */
1832 _cairo_directfb_surface_scaled_glyph_fini,/* scaled_glyph_fini */
1833 #else
1834 NULL,
1835 NULL,
1836 #endif
1837 NULL, /* paint */
1838 NULL, /* mask */
1839 NULL, /* stroke */
1840 NULL, /* fill */
1841 #if DFB_SHOW_GLYPHS
1842 _cairo_directfb_surface_show_glyphs,/* show_glyphs */
1843 #else
1844 NULL, /* show_glyphs */
1845 #endif
1846 NULL, /* snapshot */
1847 _cairo_directfb_surface_is_similar,
1848 NULL /* reset */
1852 static void
1853 cairo_directfb_surface_backend_init (IDirectFB *dfb)
1855 static int done = 0;
1857 if (done)
1858 return;
1860 if (getenv ("CAIRO_DIRECTFB_NO_ACCEL")) {
1861 #if DFB_RECTANGLES
1862 _cairo_directfb_surface_backend.fill_rectangles = NULL;
1863 #endif
1864 #if DFB_COMPOSITE
1865 _cairo_directfb_surface_backend.composite = NULL;
1866 #endif
1867 #if DFB_COMPOSITE_TRAPEZOIDS
1868 _cairo_directfb_surface_backend.composite_trapezoids = NULL;
1869 #endif
1870 #if DFB_SHOW_GLYPHS
1871 _cairo_directfb_surface_backend.scaled_font_fini = NULL;
1872 _cairo_directfb_surface_backend.scaled_glyph_fini = NULL;
1873 _cairo_directfb_surface_backend.show_glyphs = NULL;
1874 #endif
1875 D_DEBUG_AT (CairoDFB_Surface, "Acceleration disabled.\n");
1876 } else {
1877 DFBGraphicsDeviceDescription dsc;
1879 dfb->GetDeviceDescription (dfb, &dsc);
1881 #if DFB_COMPOSITE
1882 // if (!(dsc.acceleration_mask & DFXL_BLIT))
1883 // _cairo_directfb_surface_backend.composite = NULL;
1884 #endif
1886 #if DFB_COMPOSITE_TRAPEZOIDS
1887 // if (!(dsc.acceleration_mask & DFXL_TEXTRIANGLES))
1888 // _cairo_directfb_surface_backend.composite_trapezoids = NULL;
1889 #endif
1892 if (getenv ("CAIRO_DIRECTFB_ARGB_FONT")) {
1893 _directfb_argb_font = 1;
1894 D_DEBUG_AT (CairoDFB_Surface, "Using ARGB fonts.\n");
1897 done = 1;
1900 cairo_surface_t *
1901 cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
1903 cairo_directfb_surface_t *surface;
1904 DFBSurfacePixelFormat format;
1905 DFBSurfaceCapabilities caps;
1907 D_ASSERT (dfb != NULL);
1908 D_ASSERT (dfbsurface != NULL);
1910 cairo_directfb_surface_backend_init (dfb);
1912 surface = calloc (1, sizeof (cairo_directfb_surface_t));
1913 if (surface == NULL)
1914 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1916 dfbsurface->AddRef (dfbsurface);
1917 dfbsurface->GetPixelFormat (dfbsurface, &format);
1918 dfbsurface->GetSize (dfbsurface, &surface->width, &surface->height);
1919 surface->dfb = dfb;
1920 surface->dfbsurface = dfbsurface;
1921 surface->format = _directfb_to_cairo_format (format);
1922 surface->content = _directfb_format_to_content (format);
1924 dfbsurface->GetCapabilities (dfbsurface, &caps);
1925 if (caps & DSCAPS_PREMULTIPLIED)
1926 surface->blit_premultiplied = TRUE;
1928 _cairo_surface_init (&surface->base,
1929 &_cairo_directfb_surface_backend,
1930 surface->content);
1932 return &surface->base;