summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2013-08-23 19:24:58 +0100
committerRobin Watts <robin.watts@artifex.com>2013-08-30 16:26:39 +0100
commit2b2c67836932b1dada7f7f28e42fe4ed06c4e4ed (patch)
treebed929cca0ac26018ffbc9c98cf177da63562536
parent8f248600b2834fb121db4990aa756c40da8ddd0e (diff)
downloadmupdf-2b2c67836932b1dada7f7f28e42fe4ed06c4e4ed.tar.xz
Use RLE coding scheme for glyph bitmaps.
Rather than generating fz_pixmaps for glyphs, we generate fz_glyphs. fz_glyphs can either contain a pixmap, or an RLEd representation (if it's a mask, and it's smaller). Should take less memory in the cache, and should be faster to plot.
-rw-r--r--include/mupdf/fitz.h1
-rw-r--r--include/mupdf/fitz/glyph-cache.h10
-rw-r--r--include/mupdf/fitz/glyph.h137
-rw-r--r--include/mupdf/fitz/pixmap.h3
-rw-r--r--platform/win32/libmupdf.vcproj8
-rw-r--r--source/fitz/draw-device.c61
-rw-r--r--source/fitz/draw-glyph.c24
-rw-r--r--source/fitz/draw-imp.h2
-rw-r--r--source/fitz/draw-paint.c447
-rw-r--r--source/fitz/font.c56
-rw-r--r--source/fitz/glyph.c440
-rw-r--r--source/fitz/pixmap.c38
12 files changed, 1141 insertions, 86 deletions
diff --git a/include/mupdf/fitz.h b/include/mupdf/fitz.h
index 6edd0d3e..02c5778a 100644
--- a/include/mupdf/fitz.h
+++ b/include/mupdf/fitz.h
@@ -22,6 +22,7 @@
#include "mupdf/fitz/store.h"
#include "mupdf/fitz/colorspace.h"
#include "mupdf/fitz/pixmap.h"
+#include "mupdf/fitz/glyph.h"
#include "mupdf/fitz/bitmap.h"
#include "mupdf/fitz/image.h"
#include "mupdf/fitz/function.h"
diff --git a/include/mupdf/fitz/glyph-cache.h b/include/mupdf/fitz/glyph-cache.h
index 81dbd95c..e06889e0 100644
--- a/include/mupdf/fitz/glyph-cache.h
+++ b/include/mupdf/fitz/glyph-cache.h
@@ -20,11 +20,11 @@ void fz_purge_glyph_cache(fz_context *ctx);
fz_path *fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm);
fz_path *fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm);
-fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, int aa);
-fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, fz_colorspace *model, fz_irect scissor);
-fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state);
-fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, const fz_matrix *, fz_colorspace *model, fz_irect scissor);
-fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, const fz_matrix *, const fz_matrix *, fz_stroke_state *stroke, fz_irect scissor);
+fz_glyph *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, int aa);
+fz_glyph *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, fz_colorspace *model, fz_irect scissor);
+fz_glyph *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state);
+fz_glyph *fz_render_glyph(fz_context *ctx, fz_font*, int, const fz_matrix *, fz_colorspace *model, fz_irect scissor);
+fz_glyph *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, const fz_matrix *, const fz_matrix *, fz_stroke_state *stroke, fz_irect scissor);
void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, const fz_matrix *trm, void *gstate, int nestedDepth);
void fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid, int nestedDepth);
void fz_dump_glyph_cache_stats(fz_context *ctx);
diff --git a/include/mupdf/fitz/glyph.h b/include/mupdf/fitz/glyph.h
new file mode 100644
index 00000000..f2cc6cc1
--- /dev/null
+++ b/include/mupdf/fitz/glyph.h
@@ -0,0 +1,137 @@
+#ifndef MUPDF_FITZ_GLYPH_H
+#define MUPDF_FITZ_GLYPH_H
+
+#include "mupdf/fitz/system.h"
+#include "mupdf/fitz/context.h"
+#include "mupdf/fitz/math.h"
+#include "mupdf/fitz/store.h"
+#include "mupdf/fitz/colorspace.h"
+
+/*
+ Glyphs represent a run length encoded set of pixels for a 2
+ dimensional region of a plane.
+*/
+typedef struct fz_glyph_s fz_glyph;
+
+/*
+ fz_glyph_bbox: Return the bounding box for a glyph.
+*/
+fz_irect *fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph, fz_irect *bbox);
+
+/*
+ fz_glyph_width: Return the width of the glyph in pixels.
+*/
+int fz_glyph_width(fz_context *ctx, fz_glyph *glyph);
+
+/*
+ fz_glyph_height: Return the height of the glyph in pixels.
+*/
+int fz_glyph_height(fz_context *ctx, fz_glyph *glyph);
+
+/*
+ fz_new_glyph_from_pixmap: 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_new_glyph_from_8bpp_data: 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_new_glyph_from_1bpp_data: 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_keep_glyph: Take a reference to a glyph.
+
+ pix: The glyph to increment the reference for.
+
+ Returns pix. Does not throw exceptions.
+*/
+fz_glyph *fz_keep_glyph(fz_context *ctx, fz_glyph *pix);
+
+/*
+ fz_drop_glyph: Drop a reference and free a glyph.
+
+ Decrement the reference count for the glyph. When no
+ references remain the glyph will be freed.
+
+ Does not throw exceptions.
+*/
+void fz_drop_glyph(fz_context *ctx, fz_glyph *pix);
+
+/*
+ Glyphs represent a set of pixels for a 2 dimensional region of a
+ plane.
+
+ x, y: The minimum x and y coord of the region in pixels.
+
+ w, h: The width and height of the region in pixels.
+
+ samples: The sample data. The sample data is in a compressed format
+ designed to give reasonable compression, and to be fast to plot from.
+
+ The first sizeof(int) * h bytes of the table, when interpreted as
+ ints gives the offset within the data block of that lines data. An
+ offset of 0 indicates that that line is completely blank.
+
+ The data for individual lines is a sequence of bytes:
+ 00000000 = end of lines data
+ LLLLLL00 = extend the length given in the next run by the 6 L bits
+ given here.
+ LLLLLL01 = A run of length L+1 transparent pixels.
+ LLLLLE10 = A run of length L+1 solid pixels. If E then this is the
+ last run on this line.
+ LLLLLE11 = A run of length L+1 intermediate pixels followed by L+1
+ bytes of literal pixel data. If E then this is the last run
+ on this line.
+*/
+struct fz_glyph_s
+{
+ fz_storable storable;
+ int x, y, w, h;
+ fz_pixmap *pixmap;
+ int size;
+ unsigned char data[1];
+};
+
+static unsigned int fz_glyph_size(fz_context *ctx, fz_glyph *glyph);
+
+fz_irect *fz_glyph_bbox_no_ctx(fz_glyph *src, fz_irect *bbox);
+
+static inline unsigned int
+fz_glyph_size(fz_context *ctx, fz_glyph *glyph)
+{
+ if (glyph == NULL)
+ return 0;
+ return sizeof(fz_glyph) + glyph->size + fz_pixmap_size(ctx, glyph->pixmap);
+}
+
+#endif
diff --git a/include/mupdf/fitz/pixmap.h b/include/mupdf/fitz/pixmap.h
index 6e3a7d61..8be72914 100644
--- a/include/mupdf/fitz/pixmap.h
+++ b/include/mupdf/fitz/pixmap.h
@@ -300,4 +300,7 @@ void fz_unpack_tile(fz_pixmap *dst, unsigned char * restrict src, int n, int dep
*/
void fz_md5_pixmap(fz_pixmap *pixmap, unsigned char digest[16]);
+fz_pixmap *fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span);
+fz_pixmap *fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span);
+
#endif
diff --git a/platform/win32/libmupdf.vcproj b/platform/win32/libmupdf.vcproj
index 1eb86b06..e9feb82c 100644
--- a/platform/win32/libmupdf.vcproj
+++ b/platform/win32/libmupdf.vcproj
@@ -530,6 +530,10 @@
>
</File>
<File
+ RelativePath="..\..\source\fitz\glyph.c"
+ >
+ </File>
+ <File
RelativePath="..\..\source\fitz\halftone.c"
>
</File>
@@ -1001,6 +1005,10 @@
>
</File>
<File
+ RelativePath="..\..\include\mupdf\fitz\glyph.h"
+ >
+ </File>
+ <File
RelativePath="..\..\include\mupdf\fitz\hash.h"
>
</File>
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index 00b95e75..1cb76ae8 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -467,15 +467,18 @@ fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, const fz_rect *rect, fz
}
}
+
static void
-draw_glyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *msk,
+draw_glyph(unsigned char *colorbv, fz_pixmap *dst, fz_glyph *glyph,
int xorig, int yorig, const fz_irect *scissor)
{
- unsigned char *dp, *mp;
+ unsigned char *dp;
fz_irect bbox, bbox2;
int x, y, w, h;
+ int skip_x, skip_y;
+ fz_pixmap *msk;
- fz_pixmap_bbox_no_ctx(msk, &bbox);
+ fz_glyph_bbox_no_ctx(glyph, &bbox);
fz_translate_irect(&bbox, xorig, yorig);
fz_intersect_irect(&bbox, scissor); /* scissor < dst */
@@ -487,19 +490,28 @@ draw_glyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *msk,
w = bbox.x1 - bbox.x0;
h = bbox.y1 - bbox.y0;
- mp = msk->samples + (unsigned int)((y - msk->y - yorig) * msk->w + (x - msk->x - xorig));
- dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n);
+ skip_x = x - glyph->x - xorig;
+ skip_y = y - glyph->y - yorig;
- assert(msk->n == 1);
+ dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n);
- while (h--)
+ msk = glyph->pixmap;
+ if (msk == NULL)
{
- if (dst->colorspace)
- fz_paint_span_with_color(dp, mp, dst->n, w, colorbv);
- else
- fz_paint_span(dp, mp, 1, w, 255);
- dp += dst->w * dst->n;
- mp += msk->w;
+ fz_paint_glyph(colorbv, dst, dp, glyph, w, h, skip_x, skip_y);
+ }
+ else
+ {
+ unsigned char *mp = msk->samples + skip_y * msk->w + skip_x;
+ while (h--)
+ {
+ if (dst->colorspace)
+ fz_paint_span_with_color(dp, mp, dst->n, w, colorbv);
+ else
+ fz_paint_span(dp, mp, 1, w, 255);
+ dp += dst->w * dst->n;
+ mp += msk->w;
+ }
}
}
@@ -512,7 +524,7 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, const fz_matrix *ctm,
unsigned char shapebv;
float colorfv[FZ_MAX_COLORS];
fz_matrix tm, trm, trunc_trm;
- fz_pixmap *glyph;
+ fz_glyph *glyph;
int i, x, y, gid;
fz_draw_state *state = &dev->stack[dev->top];
fz_colorspace *model = state->dest->colorspace;
@@ -553,7 +565,8 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, const fz_matrix *ctm,
glyph = fz_render_glyph(dev->ctx, text->font, gid, &trunc_trm, model, scissor);
if (glyph)
{
- if (glyph->n == 1)
+ fz_pixmap *pixmap = glyph->pixmap;
+ if (pixmap == NULL || pixmap->n == 1)
{
draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor);
if (state->shape)
@@ -561,10 +574,10 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, const fz_matrix *ctm,
}
else
{
- fz_matrix mat = {glyph->w, 0.0, 0.0, glyph->h, x + glyph->x, y + glyph->y};
- fz_paint_image(state->dest, &state->scissor, state->shape, glyph, &mat, alpha * 255);
+ fz_matrix mat = {pixmap->w, 0.0, 0.0, pixmap->h, x + pixmap->x, y + pixmap->y};
+ fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &mat, alpha * 255);
}
- fz_drop_pixmap(dev->ctx, glyph);
+ fz_drop_glyph(dev->ctx, glyph);
}
else
{
@@ -594,7 +607,7 @@ fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke,
unsigned char colorbv[FZ_MAX_COLORS + 1];
float colorfv[FZ_MAX_COLORS];
fz_matrix tm, trm, trunc_trm;
- fz_pixmap *glyph;
+ fz_glyph *glyph;
int i, x, y, gid;
fz_draw_state *state = &dev->stack[dev->top];
fz_colorspace *model = state->dest->colorspace;
@@ -637,7 +650,7 @@ fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke,
draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor);
if (state->shape)
draw_glyph(colorbv, state->shape, glyph, x, y, &state->scissor);
- fz_drop_pixmap(dev->ctx, glyph);
+ fz_drop_glyph(dev->ctx, glyph);
}
else
{
@@ -666,7 +679,7 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, const fz_matrix *ctm, int accu
fz_irect bbox;
fz_pixmap *mask, *dest, *shape;
fz_matrix tm, trm, trunc_trm;
- fz_pixmap *glyph;
+ fz_glyph *glyph;
int i, x, y, gid;
fz_draw_state *state;
fz_colorspace *model;
@@ -755,7 +768,7 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, const fz_matrix *ctm, int accu
draw_glyph(NULL, mask, glyph, x, y, &bbox);
if (state[1].shape)
draw_glyph(NULL, state[1].shape, glyph, x, y, &bbox);
- fz_drop_pixmap(dev->ctx, glyph);
+ fz_drop_glyph(dev->ctx, glyph);
}
else
{
@@ -808,7 +821,7 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke
fz_irect bbox;
fz_pixmap *mask, *dest, *shape;
fz_matrix tm, trm, trunc_trm;
- fz_pixmap *glyph;
+ fz_glyph *glyph;
int i, x, y, gid;
fz_draw_state *state = push_stack(dev);
fz_colorspace *model = state->dest->colorspace;
@@ -870,7 +883,7 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke
draw_glyph(NULL, mask, glyph, x, y, &bbox);
if (shape)
draw_glyph(NULL, shape, glyph, x, y, &bbox);
- fz_drop_pixmap(dev->ctx, glyph);
+ fz_drop_glyph(dev->ctx, glyph);
}
else
{
diff --git a/source/fitz/draw-glyph.c b/source/fitz/draw-glyph.c
index 859c8762..3486cb99 100644
--- a/source/fitz/draw-glyph.c
+++ b/source/fitz/draw-glyph.c
@@ -27,7 +27,7 @@ struct fz_glyph_cache_entry_s
fz_glyph_cache_entry *lru_next;
fz_glyph_cache_entry *bucket_next;
fz_glyph_cache_entry *bucket_prev;
- fz_pixmap *val;
+ fz_glyph *val;
};
struct fz_glyph_cache_s
@@ -68,7 +68,7 @@ drop_glyph_cache_entry(fz_context *ctx, fz_glyph_cache_entry *entry)
entry->lru_prev->lru_next = entry->lru_next;
else
cache->lru_head = entry->lru_next;
- cache->total -= entry->val->w * entry->val->h;
+ cache->total -= fz_glyph_size(ctx, entry->val);
if (entry->bucket_next)
entry->bucket_next->bucket_prev = entry->bucket_prev;
if (entry->bucket_prev)
@@ -76,7 +76,7 @@ drop_glyph_cache_entry(fz_context *ctx, fz_glyph_cache_entry *entry)
else
cache->entry[entry->hash] = entry->bucket_next;
fz_drop_font(ctx, entry->key.font);
- fz_drop_pixmap(ctx, entry->val);
+ fz_drop_glyph(ctx, entry->val);
fz_free(ctx, entry);
}
@@ -130,7 +130,7 @@ fz_keep_glyph_cache(fz_context *ctx)
return ctx->glyph_cache;
}
-fz_pixmap *
+fz_glyph *
fz_render_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *stroke, fz_irect scissor)
{
if (font->ft_face)
@@ -187,12 +187,12 @@ move_to_front(fz_glyph_cache *cache, fz_glyph_cache_entry *entry)
Only supported for type 3 fonts.
This must not be inserted into the cache.
*/
-fz_pixmap *
+fz_glyph *
fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, fz_colorspace *model, fz_irect scissor)
{
fz_glyph_cache *cache;
fz_glyph_key key;
- fz_pixmap *val;
+ fz_glyph *val;
float size = fz_matrix_expansion(ctm);
int do_cache, locked, caching;
fz_matrix local_ctm = *ctm;
@@ -238,7 +238,7 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, f
if (memcmp(&entry->key, &key, sizeof(key)) == 0)
{
move_to_front(cache, entry);
- val = fz_keep_pixmap(ctx, entry->val);
+ val = fz_keep_glyph(ctx, entry->val);
fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
return val;
}
@@ -292,9 +292,9 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, f
{
if (memcmp(&entry->key, &key, sizeof(key)) == 0)
{
- fz_drop_pixmap(ctx, val);
+ fz_drop_glyph(ctx, val);
move_to_front(cache, entry);
- val = fz_keep_pixmap(ctx, entry->val);
+ val = fz_keep_glyph(ctx, entry->val);
fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
return val;
}
@@ -309,7 +309,7 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, f
if (entry->bucket_next)
entry->bucket_next->bucket_prev = entry;
cache->entry[hash] = entry;
- entry->val = fz_keep_pixmap(ctx, val);
+ entry->val = fz_keep_glyph(ctx, val);
fz_keep_font(ctx, key.font);
entry->lru_next = cache->lru_head;
@@ -319,12 +319,12 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, f
cache->lru_tail = entry;
cache->lru_head = entry;
- cache->total += val->w * val->h;
+ cache->total += fz_glyph_size(ctx, val);
while (cache->total > MAX_CACHE_SIZE)
{
#ifndef NDEBUG
cache->num_evictions++;
- cache->evicted += cache->lru_tail->val->w * cache->lru_tail->val->h;
+ cache->evicted += fz_glyph_size(ctx, cache->lru_tail->val);
#endif
drop_glyph_cache_entry(ctx, cache->lru_tail);
}
diff --git a/source/fitz/draw-imp.h b/source/fitz/draw-imp.h
index ca3f2c81..b491d91a 100644
--- a/source/fitz/draw-imp.h
+++ b/source/fitz/draw-imp.h
@@ -43,4 +43,6 @@ void fz_paint_pixmap_with_bbox(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_ire
void fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape);
void fz_blend_pixel(unsigned char dp[3], unsigned char bp[3], unsigned char sp[3], int blendmode);
+void fz_paint_glyph(unsigned char *colorbv, fz_pixmap *dst, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y);
+
#endif
diff --git a/source/fitz/draw-paint.c b/source/fitz/draw-paint.c
index 219a81eb..0ec570d5 100644
--- a/source/fitz/draw-paint.c
+++ b/source/fitz/draw-paint.c
@@ -815,3 +815,450 @@ fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk)
mp += msk->w;
}
}
+
+static inline void
+fz_paint_glyph_mask(int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
+{
+ while (h--)
+ {
+ int skip_xx, ww, len, extend;
+ unsigned char *runp;
+ unsigned char *ddp = dp;
+ int offset = ((int *)(glyph->data))[skip_y++];
+ if (offset >= 0)
+ {
+ int eol = 0;
+ runp = &glyph->data[offset];
+ extend = 0;
+ ww = w;
+ skip_xx = skip_x;
+ while (skip_xx)
+ {
+ int v = *runp++;
+ switch (v & 3)
+ {
+ case 0: /* Extend */
+ extend = v>>2;
+ len = 0;
+ break;
+ case 1: /* Transparent */
+ len = (v>>2) + 1 + (extend<<6);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ len -= skip_xx;
+ goto transparent_run;
+ }
+ break;
+ case 2: /* Solid */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ len -= skip_xx;
+ goto solid_run;
+ }
+ break;
+ default: /* Intermediate */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ runp += skip_xx;
+ len -= skip_xx;
+ goto intermediate_run;
+ }
+ runp += len;
+ break;
+ }
+ if (eol)
+ {
+ ww = 0;
+ break;
+ }
+ skip_xx -= len;
+ }
+ while (ww > 0)
+ {
+ int v = *runp++;
+ switch(v & 3)
+ {
+ case 0: /* Extend */
+ extend = v>>2;
+ break;
+ case 1: /* Transparent */
+ len = (v>>2) + 1 + (extend<<6);
+ extend = 0;
+transparent_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ ddp += len;
+ break;
+ case 2: /* Solid */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+solid_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ do
+ {
+ *ddp++ = 0xFF;
+ }
+ while (--len);
+ break;
+ default: /* Intermediate */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+intermediate_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ do
+ {
+ int v = *ddp;
+ int a = *runp++;
+ if (v == 0)
+ {
+ *ddp++ = a;
+ }
+ else
+ {
+ a = FZ_EXPAND(a);
+ *ddp = FZ_BLEND(0xFF, v, a);
+ ddp++;
+ }
+ }
+ while (--len);
+ break;
+ }
+ if (eol)
+ break;
+ }
+ }
+ dp += span;
+ }
+}
+
+static inline void
+fz_paint_glyph_alpha_N(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
+{
+ int sa = FZ_EXPAND(colorbv[n-1]);
+ while (h--)
+ {
+ int skip_xx, ww, len, extend;
+ unsigned char *runp;
+ unsigned char *ddp = dp;
+ int offset = ((int *)(glyph->data))[skip_y++];
+ if (offset >= 0)
+ {
+ int eol = 0;
+ runp = &glyph->data[offset];
+ extend = 0;
+ ww = w;
+ skip_xx = skip_x;
+ while (skip_xx)
+ {
+ int v = *runp++;
+ switch (v & 3)
+ {
+ case 0: /* Extend */
+ extend = v>>2;
+ len = 0;
+ break;
+ case 1: /* Transparent */
+ len = (v>>2) + 1 + (extend<<6);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ len -= skip_xx;
+ goto transparent_run;
+ }
+ break;
+ case 2: /* Solid */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ len -= skip_xx;
+ goto solid_run;
+ }
+ break;
+ default: /* Intermediate */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ runp += skip_xx;
+ len -= skip_xx;
+ goto intermediate_run;
+ }
+ runp += len;
+ break;
+ }
+ if (eol)
+ {
+ ww = 0;
+ break;
+ }
+ skip_xx -= len;
+ }
+ while (ww > 0)
+ {
+ int v = *runp++;
+ switch(v & 3)
+ {
+ case 0: /* Extend */
+ extend = v>>2;
+ break;
+ case 1: /* Transparent */
+ len = (v>>2) + 1 + (extend<<6);
+ extend = 0;
+transparent_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ ddp += len * n;
+ break;
+ case 2: /* Solid */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+solid_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ do
+ {
+ int k = 0;
+ do
+ {
+ *ddp = FZ_BLEND(colorbv[k++], *ddp, sa);
+ ddp++;
+ }
+ while (k != n-1);
+ *ddp = FZ_BLEND(0xFF, *ddp, sa);
+ ddp++;
+ }
+ while (--len);
+ break;
+ default: /* Intermediate */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+intermediate_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ do
+ {
+ int k = 0;
+ int a = *runp++;
+ a = FZ_COMBINE(sa, FZ_EXPAND(a));
+ do
+ {
+ *ddp = FZ_BLEND(colorbv[k++], *ddp, a);
+ ddp++;
+ }
+ while (k != n-1);
+ *ddp = FZ_BLEND(0xFF, *ddp, a);
+ ddp++;
+ }
+ while (--len);
+ break;
+ }
+ if (eol)
+ break;
+ }
+ }
+ dp += span;
+ }
+}
+
+static inline void
+fz_paint_glyph_solid_N(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
+{
+ while (h--)
+ {
+ int skip_xx, ww, len, extend;
+ unsigned char *runp;
+ unsigned char *ddp = dp;
+ int offset = ((int *)(glyph->data))[skip_y++];
+ if (offset >= 0)
+ {
+ int eol = 0;
+ runp = &glyph->data[offset];
+ extend = 0;
+ ww = w;
+ skip_xx = skip_x;
+ while (skip_xx)
+ {
+ int v = *runp++;
+ switch (v & 3)
+ {
+ case 0: /* Extend */
+ extend = v>>2;
+ len = 0;
+ break;
+ case 1: /* Transparent */
+ len = (v>>2) + 1 + (extend<<6);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ len -= skip_xx;
+ goto transparent_run;
+ }
+ break;
+ case 2: /* Solid */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ len -= skip_xx;
+ goto solid_run;
+ }
+ break;
+ default: /* Intermediate */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+ if (len > skip_xx)
+ {
+ runp += skip_xx;
+ len -= skip_xx;
+ goto intermediate_run;
+ }
+ runp += len;
+ break;
+ }
+ if (eol)
+ {
+ ww = 0;
+ break;
+ }
+ skip_xx -= len;
+ }
+ while (ww > 0)
+ {
+ int v = *runp++;
+ switch(v & 3)
+ {
+ case 0: /* Extend */
+ extend = v>>2;
+ break;
+ case 1: /* Transparent */
+ len = (v>>2) + 1 + (extend<<6);
+ extend = 0;
+transparent_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ ddp += len * n;
+ break;
+ case 2: /* Solid */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+solid_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ do
+ {
+ int k = 0;
+ do
+ {
+ *ddp++ = colorbv[k++];
+ }
+ while (k != n);
+ }
+ while (--len);
+ break;
+ default: /* Intermediate */
+ eol = v & 4;
+ len = (v>>3) + 1 + (extend<<5);
+ extend = 0;
+intermediate_run:
+ if (len > ww)
+ len = ww;
+ ww -= len;
+ do
+ {
+ int k = 0;
+ int a = *runp++;
+ a = FZ_EXPAND(a);
+ do
+ {
+ *ddp = FZ_BLEND(colorbv[k++], *ddp, a);
+ ddp++;
+ }
+ while (k != n-1);
+ *ddp = FZ_BLEND(0xFF, *ddp, a);
+ ddp++;
+ }
+ while (--len);
+ break;
+ }
+ if (eol)
+ break;
+ }
+ }
+ dp += span;
+ }
+}
+
+static inline void
+fz_paint_glyph_alpha(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
+{
+ switch (n)
+ {
+ case 4:
+ fz_paint_glyph_alpha_N(colorbv, 4, span, dp, glyph, w, h, skip_x, skip_y);
+ break;
+ case 2:
+ fz_paint_glyph_alpha_N(colorbv, 2, span, dp, glyph, w, h, skip_x, skip_y);
+ break;
+ default:
+ fz_paint_glyph_alpha_N(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
+ break;
+ }
+}
+
+static inline void
+fz_paint_glyph_solid(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
+{
+ switch (n)
+ {
+ case 4:
+ fz_paint_glyph_solid_N(colorbv, 4, span, dp, glyph, w, h, skip_x, skip_y);
+ break;
+ case 2:
+ fz_paint_glyph_solid_N(colorbv, 2, span, dp, glyph, w, h, skip_x, skip_y);
+ break;
+ default:
+ fz_paint_glyph_solid_N(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
+ break;
+ }
+}
+
+void
+fz_paint_glyph(unsigned char *colorbv, fz_pixmap *dst, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
+{
+ if (dst->colorspace)
+ {
+ if (colorbv[dst->n-1] == 255)
+ fz_paint_glyph_solid(colorbv, dst->n, dst->w * dst->n, dp, glyph, w, h, skip_x, skip_y);
+ else if (colorbv[dst->n-1] != 0)
+ fz_paint_glyph_alpha(colorbv, dst->n, dst->w * dst->n, dp, glyph, w, h, skip_x, skip_y);
+ }
+ else
+ fz_paint_glyph_mask(dst->w, dp, glyph, w, h, skip_x, skip_y);
+}
diff --git a/source/fitz/font.c b/source/fitz/font.c
index cbf4d466..1f44d096 100644
--- a/source/fitz/font.c
+++ b/source/fitz/font.c
@@ -401,58 +401,24 @@ fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm
return trm;
}
-static fz_pixmap *
+static fz_glyph *
fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap)
{
- fz_pixmap *pixmap;
- int y;
-
- pixmap = fz_new_pixmap(ctx, NULL, bitmap->width, bitmap->rows);
- pixmap->x = left;
- pixmap->y = top - bitmap->rows;
-
if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO)
- {
- for (y = 0; y < pixmap->h; y++)
- {
- unsigned char *out = pixmap->samples + (unsigned int)(y * pixmap->w);
- unsigned char *in = bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch);
- unsigned char bit = 0x80;
- int w = pixmap->w;
- while (w--)
- {
- *out++ = (*in & bit) ? 255 : 0;
- bit >>= 1;
- if (bit == 0)
- {
- bit = 0x80;
- in++;
- }
- }
- }
- }
+ return fz_new_glyph_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch);
else
- {
- for (y = 0; y < pixmap->h; y++)
- {
- memcpy(pixmap->samples + (unsigned int)(y * pixmap->w),
- bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch),
- pixmap->w);
- }
- }
-
- return pixmap;
+ return fz_new_glyph_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch);
}
/* The glyph cache lock is always taken when this is called. */
-fz_pixmap *
+fz_glyph *
fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, int aa)
{
FT_Face face = font->ft_face;
FT_Matrix m;
FT_Vector v;
FT_Error fterr;
- fz_pixmap *result;
+ fz_glyph *result;
fz_matrix local_trm = *trm;
float strength = fz_matrix_expansion(trm) * 0.02f;
@@ -561,7 +527,7 @@ retry_unhinted:
return result;
}
-fz_pixmap *
+fz_glyph *
fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state)
{
FT_Face face = font->ft_face;
@@ -573,7 +539,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat
FT_Stroker stroker;
FT_Glyph glyph;
FT_BitmapGlyph bitmap;
- fz_pixmap *pixmap;
+ fz_glyph *result;
FT_Stroker_LineJoin line_join;
fz_matrix local_trm = *trm;
@@ -666,7 +632,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat
bitmap = (FT_BitmapGlyph)glyph;
fz_try(ctx)
{
- pixmap = fz_copy_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap);
+ result = fz_copy_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap);
}
fz_always(ctx)
{
@@ -678,7 +644,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat
fz_rethrow(ctx);
}
- return pixmap;
+ return result;
}
static fz_rect *
@@ -967,7 +933,7 @@ fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm,
return bounds;
}
-fz_pixmap *
+fz_glyph *
fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_colorspace *model, fz_irect scissor)
{
fz_display_list *list;
@@ -1032,7 +998,7 @@ fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm
else
result = glyph;
- return result;
+ return fz_new_glyph_from_pixmap(ctx, result);
}
void
diff --git a/source/fitz/glyph.c b/source/fitz/glyph.c
new file mode 100644
index 00000000..0bf4c7fd
--- /dev/null
+++ b/source/fitz/glyph.c
@@ -0,0 +1,440 @@
+#include "mupdf/fitz.h"
+
+#define RLE_THRESHOLD 256
+
+fz_glyph *
+fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
+{
+ return (fz_glyph *)fz_keep_storable(ctx, &glyph->storable);
+}
+
+void
+fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
+{
+ fz_drop_storable(ctx, &glyph->storable);
+}
+
+static void
+fz_free_glyph_imp(fz_context *ctx, fz_storable *glyph_)
+{
+ fz_glyph *glyph = (fz_glyph *)glyph_;
+
+ if (glyph == NULL)
+ return;
+ 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;
+}
+
+int
+fz_glyph_width(fz_context *ctx, fz_glyph *glyph)
+{
+ return glyph->w;
+}
+
+int
+fz_glyph_height(fz_context *ctx, fz_glyph *glyph)
+{
+ return glyph->h;
+}
+
+#ifndef NDEBUG
+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
+
+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_free_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->w);
+ }
+ fz_always(ctx)
+ {
+ fz_drop_pixmap(ctx, pix);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+
+ return glyph;
+}
+
+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 = fz_malloc(ctx, sizeof(fz_glyph) + size);
+ FZ_INIT_STORABLE(glyph, 1, fz_free_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_resize_array(ctx, glyph, 1, 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_resize_array(ctx, glyph, 1, sizeof(fz_glyph));
+ FZ_INIT_STORABLE(glyph, 1, fz_free_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;
+}
+
+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 = fz_malloc(ctx, sizeof(fz_glyph) + size);
+ FZ_INIT_STORABLE(glyph, 1, fz_free_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_resize_array(ctx, glyph, 1, 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_resize_array(ctx, glyph, 1, sizeof(fz_glyph));
+ FZ_INIT_STORABLE(glyph, 1, fz_free_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;
+}
diff --git a/source/fitz/pixmap.c b/source/fitz/pixmap.c
index 6444d7a9..2cc6a98c 100644
--- a/source/fitz/pixmap.c
+++ b/source/fitz/pixmap.c
@@ -852,6 +852,44 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
return sizeof(*pix) + pix->n * pix->w * pix->h;
}
+fz_pixmap *
+fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
+{
+ fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h);
+ pixmap->x = x;
+ pixmap->y = y;
+
+ for (y = 0; y < h; y++)
+ memcpy(pixmap->samples + y * w, sp + y * span, w);
+
+ return pixmap;
+}
+
+fz_pixmap *
+fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
+{
+ fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h);
+ pixmap->x = x;
+ pixmap->y = y;
+
+ for (y = 0; y < h; y++)
+ {
+ unsigned char *out = pixmap->samples + y * w;
+ unsigned char *in = sp + y * span;
+ unsigned char bit = 0x80;
+ int ww = w;
+ while (ww--)
+ {
+ *out++ = (*in & bit) ? 255 : 0;
+ bit >>= 1;
+ if (bit == 0)
+ bit = 0x80, in++;
+ }
+ }
+
+ return pixmap;
+}
+
#ifdef ARCH_ARM
static void
fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,