pathscan.c.svn-base

来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 532 行

SVN-BASE
532
字号
#include "fitz-base.h"#include "fitz-world.h"#include "fitz-draw.h"enum { HSCALE = 17, VSCALE = 15, SF = 1 };/* * Global Edge List -- list of straight path segments for scan conversion * * Stepping along the edges is with bresenham's line algorithm. * * See Mike Abrash -- Graphics Programming Black Book (notably chapter 40) */fz_error *fz_newgel(fz_gel **gelp){	fz_gel *gel;	gel = *gelp = fz_malloc(sizeof(fz_gel));	if (!gel)		return fz_outofmem;	gel->edges = nil;	gel->cap = 512;	gel->len = 0;	gel->edges = fz_malloc(sizeof(fz_edge) * gel->cap);	if (!gel->edges) {		fz_free(gel);		return fz_outofmem;	}	gel->clip.x0 = gel->clip.y0 = INT_MAX;	gel->clip.x1 = gel->clip.y1 = INT_MIN;	gel->bbox.x0 = gel->bbox.y0 = INT_MAX;	gel->bbox.x1 = gel->bbox.y1 = INT_MIN;	return fz_okay;}voidfz_resetgel(fz_gel *gel, fz_irect clip){	if (fz_isinfiniterect(clip))	{		gel->clip.x0 = gel->clip.y0 = INT_MAX;		gel->clip.x1 = gel->clip.y1 = INT_MIN;	}	else {		gel->clip.x0 = clip.x0 * HSCALE;		gel->clip.x1 = clip.x1 * HSCALE;		gel->clip.y0 = clip.y0 * VSCALE;		gel->clip.y1 = clip.y1 * VSCALE;	}	gel->bbox.x0 = gel->bbox.y0 = INT_MAX;	gel->bbox.x1 = gel->bbox.y1 = INT_MIN;	gel->len = 0;}voidfz_dropgel(fz_gel *gel){	fz_free(gel->edges);	fz_free(gel);}fz_irectfz_boundgel(fz_gel *gel){	fz_irect bbox;	bbox.x0 = fz_idiv(gel->bbox.x0, HSCALE);	bbox.y0 = fz_idiv(gel->bbox.y0, VSCALE);	bbox.x1 = fz_idiv(gel->bbox.x1, HSCALE) + 1;	bbox.y1 = fz_idiv(gel->bbox.y1, VSCALE) + 1;	return bbox;}enum { INSIDE, OUTSIDE, LEAVE, ENTER };#define cliplerpy(v,m,x0,y0,x1,y1,t) cliplerpx(v,m,y0,x0,y1,x1,t)static intcliplerpx(int val, int m, int x0, int y0, int x1, int y1, int *out){	int v0out = m ? x0 > val : x0 < val;	int v1out = m ? x1 > val : x1 < val;	if (v0out + v1out == 0)		return INSIDE;	if (v0out + v1out == 2)		return OUTSIDE;	if (v1out)	{		*out = y0 + (y1 - y0) * (val - x0) / (x1 - x0);		return LEAVE;	}	else	{		*out = y1 + (y0 - y1) * (val - x1) / (x0 - x1);		return ENTER;	}}fz_error *fz_insertgel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1){	fz_edge *edge;	int dx, dy;	int winding;	int width;	int tmp;	int v;	int d;	int x0 = fz_floor(fx0 * HSCALE);	int y0 = fz_floor(fy0 * VSCALE);	int x1 = fz_floor(fx1 * HSCALE);	int y1 = fz_floor(fy1 * VSCALE);	d = cliplerpy(gel->clip.y0, 0, x0, y0, x1, y1, &v);	if (d == OUTSIDE) return fz_okay;	if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; }	if (d == ENTER) { y0 = gel->clip.y0; x0 = v; }	d = cliplerpy(gel->clip.y1, 1, x0, y0, x1, y1, &v);	if (d == OUTSIDE) return fz_okay;	if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; }	if (d == ENTER) { y0 = gel->clip.y1; x0 = v; }	if (y0 == y1)		return fz_okay;	if (y0 > y1) {		winding = -1;		tmp = x0; x0 = x1; x1 = tmp;		tmp = y0; y0 = y1; y1 = tmp;	}	else		winding = 1;	if (x0 < gel->bbox.x0) gel->bbox.x0 = x0;	if (x0 > gel->bbox.x1) gel->bbox.x1 = x0;	if (x1 < gel->bbox.x0) gel->bbox.x0 = x1;	if (x1 > gel->bbox.x1) gel->bbox.x1 = x1;	if (y0 < gel->bbox.y0) gel->bbox.y0 = y0;	if (y1 > gel->bbox.y1) gel->bbox.y1 = y1;	if (gel->len + 1 == gel->cap) {		int newcap = gel->cap + 512;		fz_edge *newedges = fz_realloc(gel->edges, sizeof(fz_edge) * newcap);		if (!newedges)			return fz_outofmem;		gel->cap = newcap;		gel->edges = newedges;	}	edge = &gel->edges[gel->len++];	dy = y1 - y0;	dx = x1 - x0;	width = dx < 0 ? -dx : dx;	edge->xdir = dx > 0 ? 1 : -1;	edge->ydir = winding;	edge->x = x0;	edge->y = y0;	edge->h = dy;	edge->adjdown = dy;	/* initial error term going l->r and r->l */	if (dx >= 0)		edge->e = 0;	else		edge->e = -dy + 1;	/* y-major edge */	if (dy >= width) {		edge->xmove = 0;		edge->adjup = width;	}	/* x-major edge */	else {		edge->xmove = (width / dy) * edge->xdir;		edge->adjup = width % dy;	}	return fz_okay;}voidfz_sortgel(fz_gel *gel){	fz_edge *a = gel->edges;	int n = gel->len;	int h, i, k;	fz_edge t;	h = 1;	if (n < 14) {		h = 1;	}	else {		while (h < n)			h = 3 * h + 1;		h /= 3;		h /= 3;	}	while (h > 0)	{		for (i = 0; i < n; i++) {			t = a[i];			k = i - h;			/* TODO: sort on y major, x minor */			while (k >= 0 && a[k].y > t.y) {				a[k + h] = a[k];				k -= h;			}			a[k + h] = t;		}		h /= 3;	}}/* * Active Edge List -- keep track of active edges while sweeping */fz_error *fz_newael(fz_ael **aelp){	fz_ael *ael;	ael = *aelp = fz_malloc(sizeof(fz_ael));	if (!ael)		return fz_outofmem;	ael->cap = 64;	ael->len = 0;	ael->edges = fz_malloc(sizeof(fz_edge*) * ael->cap);	if (!ael->edges) {		fz_free(ael);		return fz_outofmem;	}	return fz_okay;}voidfz_dropael(fz_ael *ael){	fz_free(ael->edges);	fz_free(ael);}static inline voidsortael(fz_edge **a, int n){	int h, i, k;	fz_edge *t;	h = 1;	if (n < 14) {		h = 1;	}	else {		while (h < n)			h = 3 * h + 1;		h /= 3;		h /= 3;	}	while (h > 0)	{		for (i = 0; i < n; i++) {			t = a[i];			k = i - h;			while (k >= 0 && a[k]->x > t->x) {				a[k + h] = a[k];				k -= h;			}			a[k + h] = t;		}		h /= 3;	}}static fz_error *insertael(fz_ael *ael, fz_gel *gel, int y, int *e){	/* insert edges that start here */	while (*e < gel->len && gel->edges[*e].y == y) {		if (ael->len + 1 == ael->cap) {			int newcap = ael->cap + 64;			fz_edge **newedges = fz_realloc(ael->edges, sizeof(fz_edge*) * newcap);			if (!newedges)				return fz_outofmem;			ael->edges = newedges;			ael->cap = newcap;		}		ael->edges[ael->len++] = &gel->edges[(*e)++];	}	/* shell-sort the edges by increasing x */	sortael(ael->edges, ael->len);	return fz_okay;}static voidadvanceael(fz_ael *ael){	fz_edge *edge;	int i = 0;	while (i < ael->len)	{		edge = ael->edges[i];		edge->h --;		/* terminator! */		if (edge->h == 0) {			ael->edges[i] = ael->edges[--ael->len];		}		else {			edge->x += edge->xmove;			edge->e += edge->adjup;			if (edge->e > 0) {				edge->x += edge->xdir;				edge->e -= edge->adjdown;			}			i ++;		}	}}/* * Scan convert */static inline voidaddspan(unsigned char *list, int x0, int x1, int xofs){	int x0pix, x0sub;	int x1pix, x1sub;	if (x0 == x1)		return;	/* x between 0 and width of bbox */	x0 -= xofs;	x1 -= xofs;	x0pix = x0 / HSCALE;	x0sub = x0 % HSCALE;	x1pix = x1 / HSCALE;	x1sub = x1 % HSCALE;	if (x0pix == x1pix)	{		list[x0pix] += x1sub - x0sub;		list[x0pix+1] += x0sub - x1sub;	}	else	{		list[x0pix] += HSCALE - x0sub;		list[x0pix+1] += x0sub;		list[x1pix] += x1sub - HSCALE;		list[x1pix+1] += -x1sub;	}}static inline voidnonzerowinding(fz_ael *ael, unsigned char *list, int xofs){	int winding = 0;	int x = 0;	int i;	for (i = 0; i < ael->len; i++)	{		if (!winding && (winding + ael->edges[i]->ydir))			x = ael->edges[i]->x;		if (winding && !(winding + ael->edges[i]->ydir))			addspan(list, x, ael->edges[i]->x, xofs);		winding += ael->edges[i]->ydir;	}}static inline voidevenodd(fz_ael *ael, unsigned char *list, int xofs){	int even = 0;	int x = 0;	int i;	for (i = 0; i < ael->len; i++)	{		if (!even)			x = ael->edges[i]->x;		else			addspan(list, x, ael->edges[i]->x, xofs);		even = !even;	}}static inline void toalpha(unsigned char *list, int n){	int d = 0;	while (n--)	{		d += *list;		*list++ = d;	}}static inline void blit(fz_pixmap *pix, int x, int y,						unsigned char *list, int skipx, int len,						unsigned char *argb, int over){	unsigned char *dst;	unsigned char cov;	dst = pix->samples + ( (y - pix->y) * pix->w + (x - pix->x) ) * pix->n;	cov = 0;	while (skipx--)	{		cov += *list;		*list = 0;		++list;	}	if (argb)		fz_path_w4i1o4(argb, list, cov, len, dst);	else if (over)		fz_path_1o1(list, cov, len, dst);	else		fz_path_1c1(list, cov, len, dst);}fz_error *fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, fz_irect clip,	fz_pixmap *pix, unsigned char *argb, int over){	fz_error *error;	unsigned char *deltas;	int y, e;	int yd, yc;	int xmin = fz_idiv(gel->bbox.x0, HSCALE);	int xmax = fz_idiv(gel->bbox.x1, HSCALE) + 1;	int xofs = xmin * HSCALE;	int skipx = clip.x0 - xmin;	int clipn = clip.x1 - clip.x0;	assert(clip.x0 >= xmin);	assert(clip.x1 <= xmax);	if (gel->len == 0)		return fz_okay;	deltas = fz_malloc(xmax - xmin + 1);	if (!deltas)		return fz_outofmem;	memset(deltas, 0, xmax - xmin + 1);	e = 0;	y = gel->edges[0].y;	yc = fz_idiv(y, VSCALE);	yd = yc;	while (ael->len > 0 || e < gel->len)	{		yc = fz_idiv(y, VSCALE);		if (yc != yd)		{			if (yd >= clip.y0 && yd < clip.y1)			{				blit(pix, xmin + skipx, yd, deltas, skipx, clipn, argb, over);			}		}		yd = yc;		error = insertael(ael, gel, y, &e);		if (error) {			fz_free(deltas);			return error;		}		if (yd >= clip.y0 && yd < clip.y1)		{			if (eofill)				evenodd(ael, deltas, xofs);			else				nonzerowinding(ael, deltas, xofs);		}		advanceael(ael);		if (ael->len > 0)			y ++;		else if (e < gel->len)			y = gel->edges[e].y;	}	if (yd >= clip.y0 && yd < clip.y1)	{		blit(pix, xmin + skipx, yd, deltas, skipx, clipn, argb, over);	}	fz_free(deltas);	return fz_okay;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?