main pixman.c
  1/* wld: pixman.c
  2 *
  3 * Copyright (c) 2013, 2014 Michael Forney
  4 *
  5 * Permission is hereby granted, free of charge, to any person obtaining a copy
  6 * of this software and associated documentation files (the "Software"), to deal
  7 * in the Software without restriction, including without limitation the rights
  8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 * copies of the Software, and to permit persons to whom the Software is
 10 * furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be included in
 13 * all copies or substantial portions of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21 * SOFTWARE.
 22 */
 23
 24#include "pixman.h"
 25#include "wld-private.h"
 26
 27#include <string.h>
 28
 29#define PIXMAN_COLOR(c)                              \
 30	{                                            \
 31		.alpha = ((c >> 24) & 0xff) * 0x101, \
 32		.red = ((c >> 16) & 0xff) * 0x101,   \
 33		.green = ((c >> 8) & 0xff) * 0x101,  \
 34		.blue = ((c >> 0) & 0xff) * 0x101,   \
 35	}
 36
 37struct pixman_renderer {
 38	struct wld_renderer base;
 39	pixman_image_t *target;
 40	pixman_glyph_cache_t *glyph_cache;
 41};
 42
 43struct pixman_buffer {
 44	struct buffer base;
 45	pixman_image_t *image;
 46};
 47
 48struct pixman_map {
 49	struct wld_exporter exporter;
 50	struct wld_destructor destructor;
 51	pixman_image_t *image;
 52};
 53
 54#include "interface/context.h"
 55#define RENDERER_IMPLEMENTS_REGION
 56#include "interface/buffer.h"
 57#include "interface/renderer.h"
 58IMPL(pixman_renderer, wld_renderer)
 59IMPL(pixman_buffer, wld_buffer)
 60
 61static struct wld_context context = { .impl = &wld_context_impl };
 62
 63EXPORT
 64struct wld_context *wld_pixman_context = &context;
 65
 66struct wld_renderer *
 67context_create_renderer(struct wld_context *context)
 68{
 69	struct pixman_renderer *renderer;
 70
 71	if (!(renderer = malloc(sizeof *renderer)))
 72		goto error0;
 73
 74	if (!(renderer->glyph_cache = pixman_glyph_cache_create()))
 75		goto error1;
 76
 77	renderer_initialize(&renderer->base, &wld_renderer_impl);
 78	renderer->target = NULL;
 79
 80	return &renderer->base;
 81
 82error1:
 83	free(renderer);
 84error0:
 85	return NULL;
 86}
 87
 88static struct buffer *
 89new_buffer(pixman_image_t *image)
 90{
 91	struct pixman_buffer *buffer;
 92
 93	if (!(buffer = malloc(sizeof *buffer)))
 94		return NULL;
 95
 96	buffer_initialize(&buffer->base, &wld_buffer_impl,
 97	                  pixman_image_get_width(image),
 98	                  pixman_image_get_height(image),
 99	                  format_pixman_to_wld(pixman_image_get_format(image)),
100	                  pixman_image_get_stride(image));
101	buffer->base.base.map = pixman_image_get_data(image);
102	buffer->image = image;
103
104	return &buffer->base;
105}
106
107struct buffer *
108context_create_buffer(struct wld_context *context,
109                      uint32_t width, uint32_t height,
110                      uint32_t format, uint32_t flags)
111{
112	struct buffer *buffer;
113	pixman_image_t *image;
114
115	image = pixman_image_create_bits(format_wld_to_pixman(format),
116	                                 width, height, NULL, 0);
117
118	if (!image)
119		goto error0;
120
121	if (!(buffer = new_buffer(image)))
122		goto error1;
123
124	return buffer;
125
126error1:
127	pixman_image_unref(image);
128error0:
129	return NULL;
130}
131
132struct buffer *
133context_import_buffer(struct wld_context *context,
134                      uint32_t type, union wld_object object,
135                      uint32_t width, uint32_t height,
136                      uint32_t format, uint32_t pitch)
137{
138	struct buffer *buffer;
139	pixman_image_t *image;
140
141	switch (type) {
142	case WLD_OBJECT_DATA:
143		image = pixman_image_create_bits(format_wld_to_pixman(format),
144		                                 width, height, object.ptr, pitch);
145		break;
146	default:
147		image = NULL;
148	}
149
150	if (!image)
151		goto error0;
152
153	if (!(buffer = new_buffer(image)))
154		goto error1;
155
156	return buffer;
157
158error1:
159	pixman_image_unref(image);
160error0:
161	return NULL;
162}
163
164void
165context_destroy(struct wld_context *context)
166{
167}
168
169uint32_t
170renderer_capabilities(struct wld_renderer *renderer, struct buffer *buffer)
171{
172	/* The pixman renderer can read and write to any buffer using it's map
173	 * implementation. */
174	return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE;
175}
176
177static void
178destroy_image(pixman_image_t *image, void *data)
179{
180	struct buffer *buffer = data;
181
182	wld_unmap(&buffer->base);
183}
184
185bool
186map_export(struct wld_exporter *exporter, struct wld_buffer *buffer,
187           uint32_t type, union wld_object *object)
188{
189	struct pixman_map *map = CONTAINER_OF(exporter, struct pixman_map, exporter);
190
191	switch (type) {
192	case WLD_PIXMAN_OBJECT_IMAGE:
193		object->ptr = pixman_image_ref(map->image);
194		return true;
195	default:
196		return false;
197	}
198}
199
200void
201map_destroy(struct wld_destructor *destructor)
202{
203	struct pixman_map *map = CONTAINER_OF(destructor, struct pixman_map, destructor);
204
205	pixman_image_unref(map->image);
206	free(map);
207}
208
209static pixman_image_t *
210pixman_image(struct buffer *buffer)
211{
212	if (buffer->base.impl == &wld_buffer_impl)
213		return pixman_image_ref(pixman_buffer(&buffer->base)->image);
214
215	union wld_object object;
216
217	if (wld_export(&buffer->base, WLD_PIXMAN_OBJECT_IMAGE, &object))
218		return object.ptr;
219
220	struct pixman_map *map;
221	pixman_image_t *image;
222
223	if (!wld_map(&buffer->base))
224		goto error0;
225
226	image = pixman_image_create_bits(format_wld_to_pixman(buffer->base.format),
227	                                 buffer->base.width, buffer->base.height,
228	                                 buffer->base.map, buffer->base.pitch);
229
230	if (!image)
231		goto error1;
232
233	if (!(map = malloc(sizeof *map)))
234		goto error2;
235
236	map->image = image;
237	map->exporter.export = &map_export;
238	wld_buffer_add_exporter(&buffer->base, &map->exporter);
239	map->destructor.destroy = &map_destroy;
240	wld_buffer_add_destructor(&buffer->base, &map->destructor);
241	pixman_image_set_destroy_function(image, &destroy_image, buffer);
242
243	return pixman_image_ref(image);
244
245error2:
246	pixman_image_unref(image);
247error1:
248	wld_unmap(&buffer->base);
249error0:
250	return NULL;
251}
252
253bool
254renderer_set_target(struct wld_renderer *base, struct buffer *buffer)
255{
256	struct pixman_renderer *renderer = pixman_renderer(base);
257
258	if (renderer->target)
259		pixman_image_unref(renderer->target);
260
261	if (buffer)
262		return (renderer->target = pixman_image(buffer));
263
264	renderer->target = NULL;
265	return true;
266}
267
268void
269renderer_fill_rectangle(struct wld_renderer *base, uint32_t color,
270                        int32_t x, int32_t y,
271                        uint32_t width, uint32_t height)
272{
273	struct pixman_renderer *renderer = pixman_renderer(base);
274	pixman_color_t pixman_color = PIXMAN_COLOR(color);
275	pixman_box32_t box = { x, y, x + width, y + height };
276
277	pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target,
278	                        &pixman_color, 1, &box);
279}
280
281void
282renderer_fill_region(struct wld_renderer *base, uint32_t color,
283                     pixman_region32_t *region)
284{
285	struct pixman_renderer *renderer = pixman_renderer(base);
286	pixman_color_t pixman_color = PIXMAN_COLOR(color);
287	pixman_box32_t *boxes;
288	int num_boxes;
289
290	boxes = pixman_region32_rectangles(region, &num_boxes);
291	pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target,
292	                        &pixman_color, num_boxes, boxes);
293}
294
295void
296renderer_copy_rectangle(struct wld_renderer *base, struct buffer *buffer,
297                        int32_t dst_x, int32_t dst_y,
298                        int32_t src_x, int32_t src_y,
299                        uint32_t width, uint32_t height)
300{
301	struct pixman_renderer *renderer = pixman_renderer(base);
302	pixman_image_t *src = pixman_image(buffer), *dst = renderer->target;
303
304	if (!src)
305		return;
306
307	pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst,
308	                         src_x, src_y, 0, 0, dst_x, dst_y, width, height);
309	pixman_image_unref(src);
310}
311
312void
313renderer_copy_region(struct wld_renderer *base, struct buffer *buffer,
314                     int32_t dst_x, int32_t dst_y,
315                     pixman_region32_t *region)
316{
317	struct pixman_renderer *renderer = pixman_renderer(base);
318	pixman_image_t *src = pixman_image(buffer), *dst = renderer->target;
319	pixman_region32_t clip;
320
321	if (!src)
322		return;
323
324	pixman_region32_init(&clip);
325	pixman_region32_copy(&clip, region);
326	pixman_region32_translate(&clip, dst_x, dst_y);
327
328	pixman_image_set_clip_region32(dst, &clip);
329	pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst,
330	                         region->extents.x1, region->extents.y1, 0, 0,
331	                         region->extents.x1 + dst_x,
332	                         region->extents.y1 + dst_y,
333	                         region->extents.x2 - region->extents.x1,
334	                         region->extents.y2 - region->extents.y1);
335	pixman_image_unref(src);
336	pixman_image_set_clip_region32(dst, NULL);
337
338	pixman_region32_fini(&clip);
339}
340
341static inline uint8_t
342reverse(uint8_t byte)
343{
344	byte = ((byte << 1) & 0xaa) | ((byte >> 1) & 0x55);
345	byte = ((byte << 2) & 0xcc) | ((byte >> 2) & 0x33);
346	byte = ((byte << 4) & 0xf0) | ((byte >> 4) & 0x0f);
347
348	return byte;
349}
350
351static pixman_image_t *
352glyph_bitmap_to_pixman_image(struct glyph *glyph)
353{
354	FT_Bitmap *bitmap = &glyph->bitmap;
355	pixman_image_t *image;
356	uint8_t *src, *dst;
357	uint32_t row, byte_index, bytes_per_row, pitch;
358
359	switch (bitmap->pixel_mode) {
360	case FT_PIXEL_MODE_MONO:
361		image = pixman_image_create_bits(PIXMAN_a1, bitmap->width,
362		                                 bitmap->rows, NULL, bitmap->pitch);
363		if (!image)
364			return NULL;
365
366		pitch = pixman_image_get_stride(image);
367		bytes_per_row = (bitmap->width + 7) / 8;
368		src = bitmap->buffer;
369		dst = (uint8_t *)pixman_image_get_data(image);
370
371		for (row = 0; row < bitmap->rows; ++row) {
372			/* Pixman's A1 format expects the bits in the opposite order
373			 * that Freetype gives us. */
374			for (byte_index = 0; byte_index < bytes_per_row; ++byte_index)
375				dst[byte_index] = reverse(src[byte_index]);
376
377			dst += pitch;
378			src += bitmap->pitch;
379		}
380		return image;
381	case FT_PIXEL_MODE_GRAY:
382		image = pixman_image_create_bits(PIXMAN_a8, bitmap->width,
383		                                 bitmap->rows, NULL, 0);
384		if (!image)
385			return NULL;
386
387		pitch = pixman_image_get_stride(image);
388		src = bitmap->buffer;
389		dst = (uint8_t *)pixman_image_get_data(image);
390
391		for (row = 0; row < bitmap->rows; ++row) {
392			memset(dst, 0, pitch);
393			memcpy(dst, src, bitmap->width);
394			dst += pitch;
395			src += bitmap->pitch;
396		}
397		return image;
398	default:
399		return NULL;
400	}
401}
402
403void
404renderer_draw_text(struct wld_renderer *base,
405                   struct font *font, uint32_t color,
406                   int32_t x, int32_t y, const char *text,
407                   uint32_t length, struct wld_extents *extents)
408{
409	struct pixman_renderer *renderer = pixman_renderer(base);
410	int ret;
411	uint32_t c;
412	struct glyph *glyph;
413	FT_UInt glyph_index;
414	pixman_glyph_t *glyphs;
415	uint32_t index = 0, origin_x = 0;
416	pixman_color_t pixman_color = PIXMAN_COLOR(color);
417	pixman_image_t *solid;
418
419	if (length == -1)
420		length = strlen(text);
421	glyphs = malloc(length * sizeof(glyphs[0]));
422	if (!glyphs)
423		return;
424	solid = pixman_image_create_solid_fill(&pixman_color);
425
426	while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length)) > 0 && c != '\0') {
427		text += ret;
428		length -= ret;
429		glyph_index = FT_Get_Char_Index(font->face, c);
430
431		if (!font_ensure_glyph(font, glyph_index))
432			continue;
433
434		glyph = font->glyphs[glyph_index];
435
436		glyphs[index].x = origin_x;
437		glyphs[index].y = 0;
438		glyphs[index].glyph = pixman_glyph_cache_lookup(renderer->glyph_cache,
439		                                                font, glyph);
440
441		/* If we don't have the glyph in our cache, do some conversions to make
442		 * pixman happy, and then insert it. */
443		if (!glyphs[index].glyph) {
444			pixman_image_t *image;
445			image = glyph_bitmap_to_pixman_image(glyph);
446
447			if (!image)
448				goto advance;
449
450			/* Insert the glyph into the cache. */
451			pixman_glyph_cache_freeze(renderer->glyph_cache);
452			glyphs[index].glyph = pixman_glyph_cache_insert(renderer->glyph_cache, font, glyph,
453			                                                -glyph->x, -glyph->y, image);
454			pixman_glyph_cache_thaw(renderer->glyph_cache);
455
456			/* The glyph cache copies the contents of the glyph bitmap. */
457			pixman_image_unref(image);
458		}
459
460		++index;
461
462	advance:
463		origin_x += glyph->advance;
464	}
465
466	pixman_composite_glyphs_no_mask(PIXMAN_OP_OVER, solid, renderer->target,
467	                                0, 0, x, y, renderer->glyph_cache,
468	                                index, glyphs);
469
470	free(glyphs);
471	pixman_image_unref(solid);
472
473	if (extents)
474		extents->advance = origin_x;
475}
476
477void
478renderer_flush(struct wld_renderer *renderer)
479{
480}
481
482void
483renderer_destroy(struct wld_renderer *base)
484{
485	struct pixman_renderer *renderer = pixman_renderer(base);
486
487	pixman_glyph_cache_destroy(renderer->glyph_cache);
488	free(renderer);
489}
490
491bool
492buffer_map(struct buffer *buffer)
493{
494	return true;
495}
496
497bool
498buffer_unmap(struct buffer *buffer)
499{
500	return true;
501}
502
503void
504buffer_destroy(struct buffer *base)
505{
506	struct pixman_buffer *buffer = pixman_buffer(&base->base);
507
508	pixman_image_unref(buffer->image);
509	free(buffer);
510}