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/draw-paint.c | |
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/draw-paint.c')
-rw-r--r-- | source/fitz/draw-paint.c | 447 |
1 files changed, 447 insertions, 0 deletions
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); +} |