diff options
author | Robin Watts <robin.watts@artifex.com> | 2013-08-23 19:24:58 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2013-08-30 16:26:39 +0100 |
commit | 2b2c67836932b1dada7f7f28e42fe4ed06c4e4ed (patch) | |
tree | bed929cca0ac26018ffbc9c98cf177da63562536 /source/fitz | |
parent | 8f248600b2834fb121db4990aa756c40da8ddd0e (diff) | |
download | mupdf-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.
Diffstat (limited to 'source/fitz')
-rw-r--r-- | source/fitz/draw-device.c | 61 | ||||
-rw-r--r-- | source/fitz/draw-glyph.c | 24 | ||||
-rw-r--r-- | source/fitz/draw-imp.h | 2 | ||||
-rw-r--r-- | source/fitz/draw-paint.c | 447 | ||||
-rw-r--r-- | source/fitz/font.c | 56 | ||||
-rw-r--r-- | source/fitz/glyph.c | 440 | ||||
-rw-r--r-- | source/fitz/pixmap.c | 38 |
7 files changed, 987 insertions, 81 deletions
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, |