497 lines
9.8 KiB
C
497 lines
9.8 KiB
C
#include "mupdf/fitz.h"
|
|
|
|
#include <string.h>
|
|
|
|
#define RLE_THRESHOLD 256
|
|
|
|
/*
|
|
Take a reference to a glyph.
|
|
|
|
pix: The glyph to increment the reference for.
|
|
|
|
Returns pix.
|
|
*/
|
|
fz_glyph *
|
|
fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
|
|
{
|
|
return fz_keep_storable(ctx, &glyph->storable);
|
|
}
|
|
|
|
/*
|
|
Drop a reference and free a glyph.
|
|
|
|
Decrement the reference count for the glyph. When no
|
|
references remain the glyph will be freed.
|
|
*/
|
|
void
|
|
fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
|
|
{
|
|
fz_drop_storable(ctx, &glyph->storable);
|
|
}
|
|
|
|
static void
|
|
fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_)
|
|
{
|
|
fz_glyph *glyph = (fz_glyph *)glyph_;
|
|
fz_drop_pixmap(ctx, glyph->pixmap);
|
|
fz_free(ctx, glyph);
|
|
}
|
|
|
|
fz_irect
|
|
fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph)
|
|
{
|
|
fz_irect bbox;
|
|
bbox.x0 = glyph->x;
|
|
bbox.y0 = glyph->y;
|
|
bbox.x1 = glyph->x + glyph->w;
|
|
bbox.y1 = glyph->y + glyph->h;
|
|
return bbox;
|
|
}
|
|
|
|
fz_irect
|
|
fz_glyph_bbox_no_ctx(fz_glyph *glyph)
|
|
{
|
|
fz_irect bbox;
|
|
bbox.x0 = glyph->x;
|
|
bbox.y0 = glyph->y;
|
|
bbox.x1 = glyph->x + glyph->w;
|
|
bbox.y1 = glyph->y + glyph->h;
|
|
return bbox;
|
|
}
|
|
|
|
/*
|
|
Return the width of the glyph in pixels.
|
|
*/
|
|
int
|
|
fz_glyph_width(fz_context *ctx, fz_glyph *glyph)
|
|
{
|
|
return glyph->w;
|
|
}
|
|
|
|
/*
|
|
Return the height of the glyph in pixels.
|
|
*/
|
|
int
|
|
fz_glyph_height(fz_context *ctx, fz_glyph *glyph)
|
|
{
|
|
return glyph->h;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
#include <stdio.h>
|
|
|
|
void
|
|
fz_dump_glyph(fz_glyph *glyph)
|
|
{
|
|
int x, y;
|
|
|
|
if (glyph->pixmap)
|
|
{
|
|
printf("pixmap glyph\n");
|
|
return;
|
|
}
|
|
printf("glyph: %dx%d @ (%d,%d)\n", glyph->w, glyph->h, glyph->x, glyph->y);
|
|
|
|
for (y = 0; y < glyph->h; y++)
|
|
{
|
|
int offset = ((int *)(glyph->data))[y];
|
|
if (offset >= 0)
|
|
{
|
|
int extend = 0;
|
|
int eol = 0;
|
|
x = glyph->w;
|
|
do
|
|
{
|
|
int v = glyph->data[offset++];
|
|
int len;
|
|
char c;
|
|
switch(v&3)
|
|
{
|
|
case 0: /* extend */
|
|
extend = v>>2;
|
|
len = 0;
|
|
break;
|
|
case 1: /* Transparent pixels */
|
|
len = 1 + (v>>2) + (extend<<6);
|
|
extend = 0;
|
|
c = '.';
|
|
break;
|
|
case 2: /* Solid pixels */
|
|
len = 1 + (v>>3) + (extend<<5);
|
|
extend = 0;
|
|
eol = v & 4;
|
|
c = (eol ? '$' :'#');
|
|
break;
|
|
default: /* Intermediate pixels */
|
|
len = 1 + (v>>3) + (extend<<5);
|
|
extend = 0;
|
|
offset += len;
|
|
eol = v & 4;
|
|
c = (eol ? '!' : '?');
|
|
break;
|
|
}
|
|
x -= len;
|
|
while (len--)
|
|
fputc(c, stdout);
|
|
if (eol)
|
|
break;
|
|
}
|
|
while (x > 0);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
Create a new glyph from a pixmap
|
|
|
|
Returns a pointer to the new glyph. Throws exception on failure to
|
|
allocate.
|
|
*/
|
|
fz_glyph *
|
|
fz_new_glyph_from_pixmap(fz_context *ctx, fz_pixmap *pix)
|
|
{
|
|
fz_glyph *glyph = NULL;
|
|
|
|
if (pix == NULL)
|
|
return NULL;
|
|
|
|
fz_var(glyph);
|
|
|
|
fz_try(ctx)
|
|
{
|
|
if (pix->n != 1 || pix->w * pix->h < RLE_THRESHOLD)
|
|
{
|
|
glyph = fz_malloc_struct(ctx, fz_glyph);
|
|
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
|
|
glyph->x = pix->x;
|
|
glyph->y = pix->y;
|
|
glyph->w = pix->w;
|
|
glyph->h = pix->h;
|
|
glyph->size = fz_pixmap_size(ctx, pix);
|
|
glyph->pixmap = fz_keep_pixmap(ctx, pix);
|
|
}
|
|
else
|
|
glyph = fz_new_glyph_from_8bpp_data(ctx, pix->x, pix->y, pix->w, pix->h, pix->samples, pix->stride);
|
|
}
|
|
fz_always(ctx)
|
|
{
|
|
fz_drop_pixmap(ctx, pix);
|
|
}
|
|
fz_catch(ctx)
|
|
{
|
|
fz_rethrow(ctx);
|
|
}
|
|
|
|
return glyph;
|
|
}
|
|
|
|
/*
|
|
Create a new glyph from 8bpp data
|
|
|
|
x, y: X and Y position for the glyph
|
|
|
|
w, h: Width and Height for the glyph
|
|
|
|
sp: Source Pointer to data
|
|
|
|
span: Increment from line to line of data
|
|
|
|
Returns a pointer to the new glyph. Throws exception on failure to
|
|
allocate.
|
|
*/
|
|
fz_glyph *
|
|
fz_new_glyph_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
|
|
{
|
|
fz_glyph *glyph = NULL;
|
|
fz_pixmap *pix = NULL;
|
|
int size, fill, yy;
|
|
unsigned char *orig_sp = sp;
|
|
|
|
fz_var(glyph);
|
|
fz_var(pix);
|
|
|
|
fz_try(ctx)
|
|
{
|
|
/* We start out by allocating space as large as the pixmap.
|
|
* If we need more than that give up on using RLE. We can
|
|
* never hope to beat the pixmap for really small sizes. */
|
|
if (w <= 6 || w * h < RLE_THRESHOLD)
|
|
goto try_pixmap;
|
|
|
|
size = h * w;
|
|
fill = h * sizeof(int);
|
|
glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(8)");
|
|
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
|
|
glyph->x = x;
|
|
glyph->y = y;
|
|
glyph->w = w;
|
|
glyph->h = h;
|
|
glyph->pixmap = NULL;
|
|
if (w == 0 || h == 0)
|
|
{
|
|
glyph->size = 0;
|
|
break;
|
|
}
|
|
for (yy=0; yy < h; yy++)
|
|
{
|
|
int nonblankfill = fill;
|
|
int nonblankfill_end = fill;
|
|
int linefill = fill;
|
|
int ww = w;
|
|
do
|
|
{
|
|
int code;
|
|
int len = ww;
|
|
int needed;
|
|
unsigned char *ep;
|
|
switch (*sp)
|
|
{
|
|
case 0:
|
|
if (len > 0x1000)
|
|
len = 0x1000;
|
|
ep = sp+len;
|
|
while (++sp != ep && *sp == 0);
|
|
code = 1;
|
|
len -= ep-sp;
|
|
ww -= len;
|
|
needed = fill + 1 + (len > 0x40);
|
|
break;
|
|
case 255:
|
|
if (len > 0x800)
|
|
len = 0x800;
|
|
ep = sp+len;
|
|
while (++sp != ep && *sp == 255);
|
|
code = 2;
|
|
len -= ep-sp;
|
|
ww -= len;
|
|
needed = fill + 1 + (len > 0x20);
|
|
break;
|
|
default:
|
|
{
|
|
unsigned char c;
|
|
if (len > 0x800)
|
|
len = 0x800;
|
|
ep = sp+len;
|
|
while (++sp != ep && (c = *sp) != 255 && c != 0);
|
|
len -= ep-sp;
|
|
ww -= len;
|
|
needed = fill + 1 + len + (len > 0x20);
|
|
code = 3;
|
|
}
|
|
}
|
|
if (needed > size)
|
|
goto try_pixmap;
|
|
if (code == 1)
|
|
{
|
|
if (len > 0x40)
|
|
glyph->data[fill++] = ((len-1)>>6)<<2;
|
|
glyph->data[fill++] = 1 | (((len-1)&63)<<2);
|
|
}
|
|
else
|
|
{
|
|
if (len > 0x20)
|
|
glyph->data[fill++] = ((len-1)>>5)<<2;
|
|
nonblankfill = fill;
|
|
glyph->data[fill++] = code | (((len-1)&31)<<3);
|
|
if (code == 3)
|
|
{
|
|
memcpy(&glyph->data[fill], sp - len, len);
|
|
fill += len;
|
|
}
|
|
nonblankfill_end = fill;
|
|
}
|
|
}
|
|
while (ww > 0);
|
|
if (nonblankfill_end == linefill)
|
|
{
|
|
((int *)(glyph->data))[yy] = -1;
|
|
fill = linefill;
|
|
}
|
|
else
|
|
{
|
|
glyph->data[nonblankfill] |= 4;
|
|
fill = nonblankfill_end;
|
|
((int *)(glyph->data))[yy] = linefill;
|
|
}
|
|
sp += span - w;
|
|
}
|
|
if (fill != size)
|
|
{
|
|
glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
|
|
size = fill;
|
|
}
|
|
glyph->size = size;
|
|
break;
|
|
|
|
/* Nasty use of a goto here, but it saves us having to exit
|
|
* and reenter the try context, and this routine is speed
|
|
* critical. */
|
|
try_pixmap:
|
|
glyph = Memento_label(fz_realloc(ctx, glyph, sizeof(fz_glyph)), "fz_glyph(8r)");
|
|
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
|
|
pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span);
|
|
glyph->x = pix->x;
|
|
glyph->y = pix->y;
|
|
glyph->w = pix->w;
|
|
glyph->h = pix->h;
|
|
glyph->size = fz_pixmap_size(ctx, pix);
|
|
glyph->pixmap = pix;
|
|
}
|
|
fz_catch(ctx)
|
|
{
|
|
fz_drop_pixmap(ctx, pix);
|
|
fz_free(ctx, glyph);
|
|
fz_rethrow(ctx);
|
|
}
|
|
|
|
return glyph;
|
|
}
|
|
|
|
/*
|
|
Create a new glyph from 1bpp data
|
|
|
|
x, y: X and Y position for the glyph
|
|
|
|
w, h: Width and Height for the glyph
|
|
|
|
sp: Source Pointer to data
|
|
|
|
span: Increment from line to line of data
|
|
|
|
Returns a pointer to the new glyph. Throws exception on failure to
|
|
allocate.
|
|
*/
|
|
fz_glyph *
|
|
fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
|
|
{
|
|
fz_pixmap *pix = NULL;
|
|
fz_glyph *glyph = NULL;
|
|
int size, fill, yy;
|
|
unsigned char *orig_sp = sp;
|
|
|
|
fz_var(glyph);
|
|
fz_var(pix);
|
|
|
|
fz_try(ctx)
|
|
{
|
|
/* We start out by allocating space as large as the pixmap.
|
|
* If we need more than that give up on using RLE. We can
|
|
* never hope to beat the pixmap for really small sizes. */
|
|
if (w <= 6 || w * h < RLE_THRESHOLD)
|
|
goto try_pixmap;
|
|
|
|
size = h * w;
|
|
fill = h * sizeof(int);
|
|
glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(1)");
|
|
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
|
|
glyph->x = x;
|
|
glyph->y = y;
|
|
glyph->w = w;
|
|
glyph->h = h;
|
|
glyph->pixmap = NULL;
|
|
if (w == 0 || h == 0)
|
|
{
|
|
glyph->size = 0;
|
|
break;
|
|
}
|
|
for (yy=0; yy < h; yy++)
|
|
{
|
|
int nonblankfill = fill;
|
|
int nonblankfill_end = fill;
|
|
int linefill = fill;
|
|
int ww = w;
|
|
int bit = 0x80;
|
|
do
|
|
{
|
|
int len = 0;
|
|
int needed;
|
|
int b = *sp & bit;
|
|
bit >>= 1;
|
|
if (bit == 0)
|
|
bit = 0x80, sp++;
|
|
ww--;
|
|
if (b == 0)
|
|
{
|
|
while (ww > 0 && len < 0xfff && (*sp & bit) == 0)
|
|
{
|
|
bit >>= 1;
|
|
if (bit == 0)
|
|
bit = 0x80, sp++;
|
|
len++;
|
|
ww--;
|
|
}
|
|
needed = fill + (len >= 0x40) + 1;
|
|
if (needed > size)
|
|
goto try_pixmap;
|
|
if (len >= 0x40)
|
|
glyph->data[fill++] = (len>>6)<<2;
|
|
glyph->data[fill++] = 1 | ((len&63)<<2);
|
|
}
|
|
else
|
|
{
|
|
while (ww > 0 && len < 0x7ff && (*sp & bit) != 0)
|
|
{
|
|
bit >>= 1;
|
|
if (bit == 0)
|
|
bit = 0x80, sp++;
|
|
len++;
|
|
ww--;
|
|
}
|
|
needed = fill + (len >= 0x20) + 1;
|
|
if (needed > size)
|
|
goto try_pixmap;
|
|
if (len >= 0x20)
|
|
glyph->data[fill++] = (len>>5)<<2;
|
|
nonblankfill = fill;
|
|
glyph->data[fill++] = 2 | ((len&31)<<3);
|
|
nonblankfill_end = fill;
|
|
}
|
|
}
|
|
while (ww > 0);
|
|
if (nonblankfill_end == linefill)
|
|
{
|
|
((int *)(glyph->data))[yy] = -1;
|
|
fill = linefill;
|
|
}
|
|
else
|
|
{
|
|
glyph->data[nonblankfill] |= 4;
|
|
fill = nonblankfill_end;
|
|
((int *)(glyph->data))[yy] = linefill;
|
|
}
|
|
sp += span - (w>>3);
|
|
}
|
|
if (fill != size)
|
|
{
|
|
glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
|
|
size = fill;
|
|
}
|
|
glyph->size = size;
|
|
break;
|
|
|
|
/* Nasty use of a goto here, but it saves us having to exit
|
|
* and reenter the try context, and this routine is speed
|
|
* critical. */
|
|
try_pixmap:
|
|
glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph));
|
|
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
|
|
pix = fz_new_pixmap_from_1bpp_data(ctx, x, y, w, h, orig_sp, span);
|
|
glyph->x = pix->x;
|
|
glyph->y = pix->y;
|
|
glyph->w = pix->w;
|
|
glyph->h = pix->h;
|
|
glyph->size = fz_pixmap_size(ctx, pix);
|
|
glyph->pixmap = pix;
|
|
}
|
|
fz_catch(ctx)
|
|
{
|
|
fz_drop_pixmap(ctx, pix);
|
|
fz_free(ctx, glyph);
|
|
fz_rethrow(ctx);
|
|
}
|
|
|
|
return glyph;
|
|
}
|