Prima

 view release on metacpan or  search on metacpan

class/Drawable/shape.c  view on Meta::CPAN

#include "apricot.h"
#include "guts.h"
#include "Drawable.h"
#include "Application.h"
#include "Drawable_private.h"

#ifdef WITH_FRIBIDI
#include <fribidi/fribidi.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

static void*
warn_malloc(ssize_t size)
{
	void * ret;
	if (!(ret = malloc(size))) {
		warn("Drawable.text_shape: not enough memory");
		return NULL;
	}
	return ret;
}

static uint32_t*
sv2uint32( SV * text, unsigned int * size, unsigned int * flags)
{
	STRLEN dlen;
	register char * src;
	uint32_t *ret;

	src = SvPV(text, dlen);
	if (prima_is_utf8_sv(text)) {
		*flags |= toUTF8;
		*size = prima_utf8_length(src, dlen);
	} else {
		*size = dlen;
	}

	if (!(ret = ( uint32_t*) warn_malloc(sizeof(uint32_t) * (*size))))
		return NULL;

	if (*flags & toUTF8 ) {
		uint32_t *dst = ret;
		while ( dlen > 0 && dst - ret < *size) {
			STRLEN charlen;
			UV uv;
			uv = prima_utf8_uvchr(src, dlen, &charlen);
			if ( uv > 0x10FFFF ) uv = 0x10FFFF;
			*(dst++) = uv;
			if ( charlen == 0 ) break;
			src  += charlen;
			dlen -= charlen;
		}
		*size = dst - ret;
	} else {
		register int i = *size;
		register uint32_t *dst = ret;
		while (i-- > 0) *(dst++) = *((unsigned char*) src++);
	}

	return ret;
}

/*
Iterator for individual shaper runs. Each run has same direction
and its indexes are increasing/decreasing monotonically. The latter is
to avoid situations where text A<PDF>B is being sent to shaper as single run AB
which might ligate.
*/

typedef struct {
	unsigned int i, vis_len;
} BidiRunRec, *PBidiRunRec;

static void
run_init(PBidiRunRec r, int visual_length)
{
	r->i       = 0;
	r->vis_len = visual_length;
}

static int
run_next(PTextShapeRec t, PBidiRunRec r)
{
	int rtl, font, start = r->i;

	if ( r->i >= r->vis_len ) return 0;

	rtl  = t->analysis[r->i];
	font = t->fonts ? t->fonts[r->i] : 0;
	for ( ; r->i < r->vis_len + 1; r->i++) {
		if (
			r->i >= r->vis_len ||          /* eol */
			(t-> analysis[r->i] != rtl) || /* rtl != ltr */
			(t->fonts && font != t->fonts[r->i])
		) {
			return r->i - start;
		}
	}

	return 0;
}

#define INVERT(_type,_start,_end)             \
{                                             \
	register _type *s = _start, *e = _end;\
	while ( s < e ) {                     \

class/Drawable/shape.c  view on Meta::CPAN

	if ( t.len == 0 ) {
		return_zero = true;
		goto EXIT;
	}

	if ( level != tsBytes ) {
		if (!(t.analysis = warn_malloc(t.len)))
			goto EXIT;
		if (!(t.v2l = warn_malloc(sizeof(uint16_t) * t.len)))
			goto EXIT;
	}

	/* MSDN, on ScriptShape: A reasonable value is (1.5 * cChars + 16) */
	t.n_glyphs_max = t.len * 2 + 16;
#define ALLOC(id,n,type) { \
	sv_##id = prima_array_new( t.n_glyphs_max * n * sizeof(uint16_t)); \
	t.id   = (type*) prima_array_get_storage(sv_##id); \
}

	ALLOC(glyphs,1,uint16_t);
	ALLOC(indexes,1,uint16_t);
	if ( shaper_type == tsFull || force_advances) {
		ALLOC(positions,2,int16_t);
		ALLOC(advances,1,uint16_t);
	} else {
		sv_positions = sv_advances = NULL_SV;
		t.positions = NULL;
		t.advances = NULL;
	}
	if ( polyfont ) {
		ALLOC(fonts,1,uint16_t);
		bzero(t.fonts, sizeof(uint16_t) * t.n_glyphs_max);
	} else {
		sv_fonts = NULL_SV;
		t.fonts = NULL;
	}
#undef ALLOC

	if ( level == tsBytes ) {
		int i;
		uint16_t * indexes;
		if ( !system_shaper(self, &t))
			goto EXIT;
		for ( i = 0, indexes = t.indexes; i < t.n_glyphs; i++)
			*(indexes++) = i;
	} else {
		if ( !shape_unicode(self, &t,
			system_shaper, shaper_type < tsFull,
			(level < tsFull) ? false : (shaper_type < tsFull), reorder)
		) goto EXIT;
	}

	if ( skip_if_simple ) {
		Bool is_simple = true;
		for ( i = 0; i < t.n_glyphs; i++) {
			if ( i != t.indexes[i] ) {
				is_simple = false;
				break;
			}
		}
		if ( is_simple && !(t.flags & toUTF8))
			for ( i = 0; i < t.len; i++) {
				if (t.text[i] > 0x7f) {
					is_simple = false;
					break;
				}
			}
		if ( is_simple ) {
			return_zero = true;
			goto EXIT;
		}
	}

	if (gp_enter) gpLEAVE;

	/* encode direction */
	if ( level != tsBytes ) {
		for ( i = 0; i < t.n_glyphs; i++) {
			if ( t.analysis[ t.indexes[i] ] & 1 )
				t.indexes[i] |= toRTL;
		}
	}
	/* add an extra index as text length */
	t.indexes[t.n_glyphs] = t.len;

	free(t.v2l );
	free(t.analysis );
	free(t.text);
	t.v2l = NULL;
	t.analysis = NULL;
	t.text = NULL;

	if (sv_fonts != NULL_SV) {
		int i, non_zero = 0;
		for ( i = 0; i < t.n_glyphs; i++) {
			if ( t.fonts[i] != 0 ) {
				non_zero = 1;
				break;
			}
		}
		if (!non_zero) {
			sv_free(sv_fonts);
			sv_fonts = NULL_SV;
		}
	}

#define BIND(x,n,d,letter) { \
	prima_array_truncate(x, (t.n_glyphs * n + d) * sizeof(uint16_t)); \
	x = sv_2mortal(prima_array_tie( x, sizeof(uint16_t), letter)); \
}
	BIND(sv_glyphs, 1, 0, "S");
	BIND(sv_indexes, 1, 1, "S");
	if ( sv_positions != NULL_SV ) BIND(sv_positions, 2, 0, "s");
	if ( sv_advances  != NULL_SV ) BIND(sv_advances,  1, 0, "S");
	if ( sv_fonts     != NULL_SV ) BIND(sv_fonts,     1, 0, "S");
#undef BIND

	return newSVsv(call_perl(self, "new_glyph_obj", "<SSSSS",
		sv_glyphs, sv_indexes, sv_advances, sv_positions, sv_fonts
	));



( run in 2.162 seconds using v1.01-cache-2.11-cpan-a49fcb8fa48 )