| 1 | #include "mupdf/fitz.h" | 
|---|
| 2 | #include "draw-imp.h" | 
|---|
| 3 |  | 
|---|
| 4 | #include <assert.h> | 
|---|
| 5 | #include <stdlib.h> | 
|---|
| 6 | #include <string.h> | 
|---|
| 7 |  | 
|---|
| 8 | #undef DEBUG_SCAN_CONVERTER | 
|---|
| 9 |  | 
|---|
| 10 | /* Define ourselves a 'fixed' type for clarity */ | 
|---|
| 11 | typedef int fixed; | 
|---|
| 12 |  | 
|---|
| 13 | #define fixed_shift 8 | 
|---|
| 14 | #define float2fixed(x) ((int)((x)*(1<<fixed_shift))) | 
|---|
| 15 | #define fixed2int(x) ((int)((x)>>fixed_shift)) | 
|---|
| 16 | #define fixed_half (1<<(fixed_shift-1)) | 
|---|
| 17 | #define fixed_1 (1<<fixed_shift) | 
|---|
| 18 | #define int2fixed(x) ((x)<<fixed_shift) | 
|---|
| 19 |  | 
|---|
| 20 | enum | 
|---|
| 21 | { | 
|---|
| 22 | DIRN_UNSET = -1, | 
|---|
| 23 | DIRN_UP = 0, | 
|---|
| 24 | DIRN_DOWN = 1 | 
|---|
| 25 | }; | 
|---|
| 26 |  | 
|---|
| 27 | typedef struct | 
|---|
| 28 | { | 
|---|
| 29 | fixed left; | 
|---|
| 30 | fixed right; | 
|---|
| 31 | fixed y; | 
|---|
| 32 | signed char d; /* 0 up (or horiz), 1 down, -1 uninited */ | 
|---|
| 33 |  | 
|---|
| 34 | /* unset == 1, iff the values in the above are unset */ | 
|---|
| 35 | unsigned char unset; | 
|---|
| 36 | /* can_save == 1, iff we are eligible to 'save'. i.e. if we | 
|---|
| 37 | * have not yet output a cursor, and have not detected | 
|---|
| 38 | * any line segments completely out of range. */ | 
|---|
| 39 | unsigned char can_save; | 
|---|
| 40 | unsigned char saved; | 
|---|
| 41 |  | 
|---|
| 42 | fixed save_left; | 
|---|
| 43 | fixed save_right; | 
|---|
| 44 | int save_iy; | 
|---|
| 45 | int save_d; | 
|---|
| 46 | } | 
|---|
| 47 | cursor_t; | 
|---|
| 48 |  | 
|---|
| 49 | typedef struct fz_edgebuffer_s | 
|---|
| 50 | { | 
|---|
| 51 | fz_rasterizer super; | 
|---|
| 52 | int app; | 
|---|
| 53 | int sorted; | 
|---|
| 54 | int n; | 
|---|
| 55 | int index_cap; | 
|---|
| 56 | int *index; | 
|---|
| 57 | int table_cap; | 
|---|
| 58 | int *table; | 
|---|
| 59 |  | 
|---|
| 60 | /* cursor section, for use with any part of pixel mode */ | 
|---|
| 61 | cursor_t cursor[3]; | 
|---|
| 62 | } fz_edgebuffer; | 
|---|
| 63 |  | 
|---|
| 64 | static fz_rasterizer_insert_fn fz_insert_edgebuffer_app; | 
|---|
| 65 | static fz_rasterizer_insert_fn fz_insert_edgebuffer; | 
|---|
| 66 |  | 
|---|
| 67 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 68 | int debugging_scan_converter = 1; | 
|---|
| 69 |  | 
|---|
| 70 | static void | 
|---|
| 71 | fz_edgebuffer_print(fz_context *ctx, fz_output *out, fz_edgebuffer * edgebuffer) | 
|---|
| 72 | { | 
|---|
| 73 | int i; | 
|---|
| 74 | int height = edgebuffer->super.clip.y1 - edgebuffer->super.clip.y0; | 
|---|
| 75 |  | 
|---|
| 76 | fz_write_printf(ctx, out, "Edgebuffer %x\n", edgebuffer); | 
|---|
| 77 | fz_write_printf(ctx, out, "xmin=%x xmax=%x base=%x height=%x\n", | 
|---|
| 78 | edgebuffer->super.clip.x0, edgebuffer->super.clip.x1, edgebuffer->super.clip.y0, height); | 
|---|
| 79 | for (i=0; i < height; i++) { | 
|---|
| 80 | int  offset = edgebuffer->index[i]; | 
|---|
| 81 | int *row = &edgebuffer->table[offset]; | 
|---|
| 82 | int count = *row++; | 
|---|
| 83 | assert ((count & 1) == 0); | 
|---|
| 84 | fz_write_printf(ctx, out, "%x @ %x: %d =", i, offset, count); | 
|---|
| 85 | while (count-- > 0) { | 
|---|
| 86 | int v = *row++; | 
|---|
| 87 | fz_write_printf(ctx, out, " %x:%d", v&~1, v&1); | 
|---|
| 88 | } | 
|---|
| 89 | fz_write_printf(ctx, out, "\n"); | 
|---|
| 90 | } | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 | static void | 
|---|
| 94 | fz_edgebuffer_print_app(fz_context *ctx, fz_output *out, fz_edgebuffer * edgebuffer) | 
|---|
| 95 | { | 
|---|
| 96 | int i; | 
|---|
| 97 | int height = edgebuffer->super.clip.y1 - edgebuffer->super.clip.y0; | 
|---|
| 98 |  | 
|---|
| 99 | fz_write_printf(ctx, out, "Edgebuffer %x\n", edgebuffer); | 
|---|
| 100 | fz_write_printf(ctx, out, "xmin=%x xmax=%x base=%x height=%x\n", | 
|---|
| 101 | edgebuffer->super.clip.x0, edgebuffer->super.clip.x1, edgebuffer->super.clip.y0, height); | 
|---|
| 102 | if (edgebuffer->table == NULL) | 
|---|
| 103 | return; | 
|---|
| 104 | for (i=0; i < height; i++) { | 
|---|
| 105 | int  offset = edgebuffer->index[i]; | 
|---|
| 106 | int *row = &edgebuffer->table[offset]; | 
|---|
| 107 | int count = *row++; | 
|---|
| 108 | int count0 = count; | 
|---|
| 109 | fz_write_printf(ctx, out, "%x @ %x: %d =", i, offset, count); | 
|---|
| 110 | while (count-- > 0) { | 
|---|
| 111 | int l = *row++; | 
|---|
| 112 | int r = *row++; | 
|---|
| 113 | fz_write_printf(ctx, out, " %x:%x", l, r); | 
|---|
| 114 | } | 
|---|
| 115 | assert((count0 & 1) == 0); (void)count0; | 
|---|
| 116 | fz_write_printf(ctx, out, "\n"); | 
|---|
| 117 | } | 
|---|
| 118 | } | 
|---|
| 119 | #endif | 
|---|
| 120 |  | 
|---|
| 121 | static void fz_drop_edgebuffer(fz_context *ctx, fz_rasterizer *r) | 
|---|
| 122 | { | 
|---|
| 123 | fz_edgebuffer *eb = (fz_edgebuffer *)r; | 
|---|
| 124 |  | 
|---|
| 125 | if (eb) | 
|---|
| 126 | { | 
|---|
| 127 | fz_free(ctx, eb->index); | 
|---|
| 128 | fz_free(ctx, eb->table); | 
|---|
| 129 | } | 
|---|
| 130 | fz_free(ctx, eb); | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | static void index_edgebuffer_insert(fz_context *ctx, fz_rasterizer *ras, float fsx, float fsy, float fex, float fey, int rev) | 
|---|
| 134 | { | 
|---|
| 135 | fz_edgebuffer *eb = (fz_edgebuffer *)ras; | 
|---|
| 136 | int iminy, imaxy; | 
|---|
| 137 | int height = eb->super.clip.y1 - eb->super.clip.y0; | 
|---|
| 138 |  | 
|---|
| 139 | if (fsy == fey) | 
|---|
| 140 | return; | 
|---|
| 141 |  | 
|---|
| 142 | if (fsx < fex) | 
|---|
| 143 | { | 
|---|
| 144 | if (fsx < eb->super.bbox.x0) eb->super.bbox.x0 = fsx; | 
|---|
| 145 | if (fex > eb->super.bbox.x1) eb->super.bbox.x1 = fex; | 
|---|
| 146 | } | 
|---|
| 147 | else | 
|---|
| 148 | { | 
|---|
| 149 | if (fsx > eb->super.bbox.x1) eb->super.bbox.x1 = fsx; | 
|---|
| 150 | if (fex < eb->super.bbox.x0) eb->super.bbox.x0 = fex; | 
|---|
| 151 | } | 
|---|
| 152 | if (fsy < fey) | 
|---|
| 153 | { | 
|---|
| 154 | if (fsy < eb->super.bbox.y0) eb->super.bbox.y0 = fsy; | 
|---|
| 155 | if (fey > eb->super.bbox.y1) eb->super.bbox.y1 = fey; | 
|---|
| 156 | } | 
|---|
| 157 | else | 
|---|
| 158 | { | 
|---|
| 159 | if (fey < eb->super.bbox.y0) eb->super.bbox.y0 = fey; | 
|---|
| 160 | if (fsy > eb->super.bbox.y1) eb->super.bbox.y1 = fsy; | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | /* To strictly match, this should be: | 
|---|
| 164 | * iminy = int2fixed(float2fixed(fsy)) | 
|---|
| 165 | * imaxy = int2fixed(float2fixed(fsx)) | 
|---|
| 166 | * but this is faster. It can round differently, | 
|---|
| 167 | * (on some machines at least) hence the iminy--; below. | 
|---|
| 168 | */ | 
|---|
| 169 | iminy = (int)fsy; | 
|---|
| 170 | imaxy = (int)fey; | 
|---|
| 171 |  | 
|---|
| 172 | if (iminy > imaxy) | 
|---|
| 173 | { | 
|---|
| 174 | int t; | 
|---|
| 175 | t = iminy; iminy = imaxy; imaxy = t; | 
|---|
| 176 | } | 
|---|
| 177 | imaxy++; | 
|---|
| 178 | iminy--; | 
|---|
| 179 |  | 
|---|
| 180 | imaxy -= eb->super.clip.y0; | 
|---|
| 181 | if (imaxy < 0) | 
|---|
| 182 | return; | 
|---|
| 183 | iminy -= eb->super.clip.y0; | 
|---|
| 184 | if (iminy < 0) | 
|---|
| 185 | iminy = 0; | 
|---|
| 186 | else if (iminy > height) | 
|---|
| 187 | return; | 
|---|
| 188 | if (imaxy > height-1) | 
|---|
| 189 | imaxy = height-1; | 
|---|
| 190 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 191 | if (debugging_scan_converter) | 
|---|
| 192 | fprintf(stderr, "%x->%x:%d\n", iminy, imaxy, eb->n); | 
|---|
| 193 | #endif | 
|---|
| 194 | eb->index[iminy] += eb->n; | 
|---|
| 195 | eb->index[imaxy+1] -= eb->n; | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | static void fz_postindex_edgebuffer(fz_context *ctx, fz_rasterizer *r) | 
|---|
| 199 | { | 
|---|
| 200 | fz_edgebuffer *eb = (fz_edgebuffer *)r; | 
|---|
| 201 | int height = eb->super.clip.y1 - eb->super.clip.y0 + 1; | 
|---|
| 202 | int n = eb->n; | 
|---|
| 203 | int total = 0; | 
|---|
| 204 | int delta = 0; | 
|---|
| 205 | int i; | 
|---|
| 206 |  | 
|---|
| 207 | eb->super.fns.insert = (eb->app ? fz_insert_edgebuffer_app : fz_insert_edgebuffer); | 
|---|
| 208 |  | 
|---|
| 209 | for (i = 0; i < height; i++) | 
|---|
| 210 | { | 
|---|
| 211 | delta += eb->index[i]; | 
|---|
| 212 | eb->index[i] = total; | 
|---|
| 213 | total += 1 + delta*n; | 
|---|
| 214 | } | 
|---|
| 215 | assert(delta == 0); | 
|---|
| 216 |  | 
|---|
| 217 | if (eb->table_cap < total) | 
|---|
| 218 | { | 
|---|
| 219 | eb->table = fz_realloc_array(ctx, eb->table, total, int); | 
|---|
| 220 | eb->table_cap = total; | 
|---|
| 221 | } | 
|---|
| 222 |  | 
|---|
| 223 | for (i = 0; i < height; i++) | 
|---|
| 224 | { | 
|---|
| 225 | eb->table[eb->index[i]] = 0; | 
|---|
| 226 | } | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | static int fz_reset_edgebuffer(fz_context *ctx, fz_rasterizer *r) | 
|---|
| 230 | { | 
|---|
| 231 | fz_edgebuffer *eb = (fz_edgebuffer *)r; | 
|---|
| 232 | int height = eb->super.clip.y1 - eb->super.clip.y0 + 1; | 
|---|
| 233 | int n; | 
|---|
| 234 |  | 
|---|
| 235 | eb->sorted = 0; | 
|---|
| 236 |  | 
|---|
| 237 | if (eb->index_cap < height) | 
|---|
| 238 | { | 
|---|
| 239 | eb->index = fz_realloc_array(ctx, eb->index, height, int); | 
|---|
| 240 | eb->index_cap = height; | 
|---|
| 241 | } | 
|---|
| 242 | memset(eb->index, 0, sizeof(int) * height); | 
|---|
| 243 |  | 
|---|
| 244 | n = 1; | 
|---|
| 245 |  | 
|---|
| 246 | if (eb->app) | 
|---|
| 247 | { | 
|---|
| 248 | n = 2; | 
|---|
| 249 | eb->cursor[0].saved = 0; | 
|---|
| 250 | eb->cursor[0].unset = 1; | 
|---|
| 251 | eb->cursor[0].can_save = 1; | 
|---|
| 252 | eb->cursor[0].d = DIRN_UNSET; | 
|---|
| 253 | eb->cursor[1].saved = 0; | 
|---|
| 254 | eb->cursor[1].unset = 1; | 
|---|
| 255 | eb->cursor[1].can_save = 1; | 
|---|
| 256 | eb->cursor[1].d = DIRN_UNSET; | 
|---|
| 257 | eb->cursor[2].saved = 0; | 
|---|
| 258 | eb->cursor[2].unset = 1; | 
|---|
| 259 | eb->cursor[2].can_save = 1; | 
|---|
| 260 | eb->cursor[2].d = DIRN_UNSET; | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | eb->n = n; | 
|---|
| 264 |  | 
|---|
| 265 | eb->super.fns.insert = index_edgebuffer_insert; | 
|---|
| 266 | return 1; | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | static void mark_line(fz_context *ctx, fz_edgebuffer *eb, fixed sx, fixed sy, fixed ex, fixed ey) | 
|---|
| 270 | { | 
|---|
| 271 | int base_y = eb->super.clip.y0; | 
|---|
| 272 | int height = eb->super.clip.y1 - eb->super.clip.y0; | 
|---|
| 273 | int *table = eb->table; | 
|---|
| 274 | int *index = eb->index; | 
|---|
| 275 | int delta; | 
|---|
| 276 | int iy, ih; | 
|---|
| 277 | fixed clip_sy, clip_ey; | 
|---|
| 278 | int dirn = DIRN_UP; | 
|---|
| 279 | int *row; | 
|---|
| 280 |  | 
|---|
| 281 | if (fixed2int(sy + fixed_half-1) == fixed2int(ey + fixed_half-1)) | 
|---|
| 282 | return; | 
|---|
| 283 | if (sy > ey) { | 
|---|
| 284 | int t; | 
|---|
| 285 | t = sy; sy = ey; ey = t; | 
|---|
| 286 | t = sx; sx = ex; ex = t; | 
|---|
| 287 | dirn = DIRN_DOWN; | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | if (fixed2int(sx) < eb->super.bbox.x0) | 
|---|
| 291 | eb->super.bbox.x0 = fixed2int(sx); | 
|---|
| 292 | if (fixed2int(sx + fixed_1 - 1) > eb->super.bbox.x1) | 
|---|
| 293 | eb->super.bbox.x1 = fixed2int(sx + fixed_1 - 1); | 
|---|
| 294 | if (fixed2int(ex) < eb->super.bbox.x0) | 
|---|
| 295 | eb->super.bbox.x0 = fixed2int(ex); | 
|---|
| 296 | if (fixed2int(ex + fixed_1 - 1) > eb->super.bbox.x1) | 
|---|
| 297 | eb->super.bbox.x1 = fixed2int(ex + fixed_1 - 1); | 
|---|
| 298 |  | 
|---|
| 299 | if (fixed2int(sy) < eb->super.bbox.y0) | 
|---|
| 300 | eb->super.bbox.y0 = fixed2int(sy); | 
|---|
| 301 | if (fixed2int(ey + fixed_1 - 1) > eb->super.bbox.y1) | 
|---|
| 302 | eb->super.bbox.y1 = fixed2int(ey + fixed_1 - 1); | 
|---|
| 303 |  | 
|---|
| 304 | /* Lines go from sy to ey, closed at the start, open at the end. */ | 
|---|
| 305 | /* We clip them to a region to make them closed at both ends. */ | 
|---|
| 306 | /* Thus the unset scanline marked (>= sy) is: */ | 
|---|
| 307 | clip_sy = ((sy + fixed_half - 1) & ~(fixed_1-1)) | fixed_half; | 
|---|
| 308 | /* The last scanline marked (< ey) is: */ | 
|---|
| 309 | clip_ey = ((ey - fixed_half - 1) & ~(fixed_1-1)) | fixed_half; | 
|---|
| 310 | /* Now allow for banding */ | 
|---|
| 311 | if (clip_sy < int2fixed(base_y) + fixed_half) | 
|---|
| 312 | clip_sy = int2fixed(base_y) + fixed_half; | 
|---|
| 313 | if (ey <= clip_sy) | 
|---|
| 314 | return; | 
|---|
| 315 | if (clip_ey > int2fixed(base_y + height - 1) + fixed_half) | 
|---|
| 316 | clip_ey = int2fixed(base_y + height - 1) + fixed_half; | 
|---|
| 317 | if (sy > clip_ey) | 
|---|
| 318 | return; | 
|---|
| 319 | delta = clip_sy - sy; | 
|---|
| 320 | if (delta > 0) | 
|---|
| 321 | { | 
|---|
| 322 | int dx = ex - sx; | 
|---|
| 323 | int dy = ey - sy; | 
|---|
| 324 | int advance = (int)(((int64_t)dx * delta + (dy>>1)) / dy); | 
|---|
| 325 | sx += advance; | 
|---|
| 326 | sy += delta; | 
|---|
| 327 | } | 
|---|
| 328 | ex -= sx; | 
|---|
| 329 | ey -= sy; | 
|---|
| 330 | clip_ey -= clip_sy; | 
|---|
| 331 | delta = ey - clip_ey; | 
|---|
| 332 | if (delta > 0) | 
|---|
| 333 | { | 
|---|
| 334 | int advance = (int)(((int64_t)ex * delta + (ey>>1)) / ey); | 
|---|
| 335 | ex -= advance; | 
|---|
| 336 | ey -= delta; | 
|---|
| 337 | } | 
|---|
| 338 | ih = fixed2int(ey); | 
|---|
| 339 | assert(ih >= 0); | 
|---|
| 340 | iy = fixed2int(sy) - base_y; | 
|---|
| 341 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 342 | if (debugging_scan_converter) | 
|---|
| 343 | fz_write_printf(ctx, fz_stderr(ctx), "	iy=%x ih=%x\n", iy, ih); | 
|---|
| 344 | #endif | 
|---|
| 345 | assert(iy >= 0 && iy < height); | 
|---|
| 346 | /* We always cross at least one scanline */ | 
|---|
| 347 | row = &table[index[iy]]; | 
|---|
| 348 | *row = (*row)+1; /* Increment the count */ | 
|---|
| 349 | row[*row] = (sx&~1) | dirn; | 
|---|
| 350 | if (ih == 0) | 
|---|
| 351 | return; | 
|---|
| 352 | if (ex >= 0) { | 
|---|
| 353 | int x_inc, n_inc, f; | 
|---|
| 354 |  | 
|---|
| 355 | /* We want to change sx by ex in ih steps. So each step, we add | 
|---|
| 356 | * ex/ih to sx. That's x_inc + n_inc/ih. | 
|---|
| 357 | */ | 
|---|
| 358 | x_inc = ex/ih; | 
|---|
| 359 | n_inc = ex-(x_inc*ih); | 
|---|
| 360 | f	 = ih>>1; | 
|---|
| 361 | delta = ih; | 
|---|
| 362 | do { | 
|---|
| 363 | int count; | 
|---|
| 364 | iy++; | 
|---|
| 365 | sx += x_inc; | 
|---|
| 366 | f  -= n_inc; | 
|---|
| 367 | if (f < 0) { | 
|---|
| 368 | f += ih; | 
|---|
| 369 | sx++; | 
|---|
| 370 | } | 
|---|
| 371 | assert(iy >= 0 && iy < height); | 
|---|
| 372 | row = &table[index[iy]]; | 
|---|
| 373 | count = *row = (*row)+1; /* Increment the count */ | 
|---|
| 374 | row[count] = (sx&~1) | dirn; | 
|---|
| 375 | } while (--delta); | 
|---|
| 376 | } else { | 
|---|
| 377 | int x_dec, n_dec, f; | 
|---|
| 378 |  | 
|---|
| 379 | ex = -ex; | 
|---|
| 380 | /* We want to change sx by ex in ih steps. So each step, we subtract | 
|---|
| 381 | * ex/ih from sx. That's x_dec + n_dec/ih. | 
|---|
| 382 | */ | 
|---|
| 383 | x_dec = ex/ih; | 
|---|
| 384 | n_dec = ex-(x_dec*ih); | 
|---|
| 385 | f	 = ih>>1; | 
|---|
| 386 | delta = ih; | 
|---|
| 387 | do { | 
|---|
| 388 | int count; | 
|---|
| 389 | iy++; | 
|---|
| 390 | sx -= x_dec; | 
|---|
| 391 | f  -= n_dec; | 
|---|
| 392 | if (f < 0) { | 
|---|
| 393 | f += ih; | 
|---|
| 394 | sx--; | 
|---|
| 395 | } | 
|---|
| 396 | assert(iy >= 0 && iy < height); | 
|---|
| 397 | row = &table[index[iy]]; | 
|---|
| 398 | count = *row = (*row)+1; /* Increment the count */ | 
|---|
| 399 | row[count] = (sx&~1) | dirn; | 
|---|
| 400 | } while (--delta); | 
|---|
| 401 | } | 
|---|
| 402 | } | 
|---|
| 403 |  | 
|---|
| 404 | static void fz_insert_edgebuffer(fz_context *ctx, fz_rasterizer *ras, float fsx, float fsy, float fex, float fey, int rev) | 
|---|
| 405 | { | 
|---|
| 406 | fz_edgebuffer *eb = (fz_edgebuffer *)ras; | 
|---|
| 407 | fixed sx = float2fixed(fsx); | 
|---|
| 408 | fixed sy = float2fixed(fsy); | 
|---|
| 409 | fixed ex = float2fixed(fex); | 
|---|
| 410 | fixed ey = float2fixed(fey); | 
|---|
| 411 |  | 
|---|
| 412 | mark_line(ctx, eb, sx, sy, ex, ey); | 
|---|
| 413 | } | 
|---|
| 414 |  | 
|---|
| 415 | static inline void | 
|---|
| 416 | cursor_output(fz_edgebuffer * FZ_RESTRICT eb, int rev, int iy) | 
|---|
| 417 | { | 
|---|
| 418 | int *row; | 
|---|
| 419 | int count; | 
|---|
| 420 | int height = eb->super.clip.y1 - eb->super.clip.y0; | 
|---|
| 421 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 422 |  | 
|---|
| 423 | rev &= 1; /* Edge label 0 is forwards, 1 and 2 are reverse */ | 
|---|
| 424 |  | 
|---|
| 425 | if (iy >= 0 && iy < height) { | 
|---|
| 426 | if (cr->can_save) { | 
|---|
| 427 | /* Save it for later in case we join up */ | 
|---|
| 428 | cr->save_left = cr->left; | 
|---|
| 429 | cr->save_right = cr->right; | 
|---|
| 430 | cr->save_iy = iy; | 
|---|
| 431 | cr->save_d = cr->d; | 
|---|
| 432 | cr->saved = 1; | 
|---|
| 433 | } else { | 
|---|
| 434 | /* Enter it into the table */ | 
|---|
| 435 | row = &eb->table[eb->index[iy]]; | 
|---|
| 436 | if (cr->d == DIRN_UNSET) | 
|---|
| 437 | { | 
|---|
| 438 | /* Move 0 0; line 10 0; line 0 0; */ | 
|---|
| 439 | /* FIXME */ | 
|---|
| 440 | } | 
|---|
| 441 | else | 
|---|
| 442 | { | 
|---|
| 443 | *row = count = (*row)+1; /* Increment the count */ | 
|---|
| 444 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 445 | if (debugging_scan_converter) | 
|---|
| 446 | fprintf(stderr, "row: %x: %x->%x %c\n", iy, cr->left, cr->right, (cr->d^rev) == DIRN_UP ? '^' : (cr->d^rev) == DIRN_DOWN ? 'v' : '-'); | 
|---|
| 447 | #endif | 
|---|
| 448 | assert(count <= (eb->index[iy+1] - eb->index[iy] - 1)/2); | 
|---|
| 449 | row[2 * count - 1] = (cr->left&~1) | (cr->d ^ rev); | 
|---|
| 450 | row[2 * count] = cr->right; | 
|---|
| 451 | } | 
|---|
| 452 | } | 
|---|
| 453 | } | 
|---|
| 454 | cr->can_save = 0; | 
|---|
| 455 | } | 
|---|
| 456 |  | 
|---|
| 457 | static inline void | 
|---|
| 458 | cursor_output_inrange(fz_edgebuffer * FZ_RESTRICT eb, int rev, int iy) | 
|---|
| 459 | { | 
|---|
| 460 | int *row; | 
|---|
| 461 | int count; | 
|---|
| 462 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 463 |  | 
|---|
| 464 | rev &= 1; /* Edge label 0 is forwards, 1 and 2 are reverse */ | 
|---|
| 465 |  | 
|---|
| 466 | assert(iy >= 0 && iy < eb->super.clip.y1 - eb->super.clip.y0); | 
|---|
| 467 | if (cr->can_save) { | 
|---|
| 468 | /* Save it for later in case we join up */ | 
|---|
| 469 | cr->save_left = cr->left; | 
|---|
| 470 | cr->save_right = cr->right; | 
|---|
| 471 | cr->save_iy = iy; | 
|---|
| 472 | cr->save_d = cr->d; | 
|---|
| 473 | cr->saved = 1; | 
|---|
| 474 | } else { | 
|---|
| 475 | /* Enter it into the table */ | 
|---|
| 476 | assert(cr->d != DIRN_UNSET); | 
|---|
| 477 |  | 
|---|
| 478 | row = &eb->table[eb->index[iy]]; | 
|---|
| 479 | *row = count = (*row)+1; /* Increment the count */ | 
|---|
| 480 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 481 | if (debugging_scan_converter) | 
|---|
| 482 | printf( "row= %x: %x->%x %c\n", iy, cr->left, cr->right, (cr->d^rev) == DIRN_UP ? '^' : (cr->d^rev) == DIRN_DOWN ? 'v' : '-'); | 
|---|
| 483 | #endif | 
|---|
| 484 | row[2 * count - 1] = (cr->left&~1) | (cr->d ^ rev); | 
|---|
| 485 | row[2 * count] = cr->right; | 
|---|
| 486 | } | 
|---|
| 487 | cr->can_save = 0; | 
|---|
| 488 | } | 
|---|
| 489 |  | 
|---|
| 490 | /* Step the cursor in y, allowing for maybe crossing a scanline */ | 
|---|
| 491 | static inline void | 
|---|
| 492 | cursor_step(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 493 | { | 
|---|
| 494 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 495 | int new_iy; | 
|---|
| 496 | int base = eb->super.clip.y0; | 
|---|
| 497 | int iy = fixed2int(cr->y) - base; | 
|---|
| 498 |  | 
|---|
| 499 | cr->y += dy; | 
|---|
| 500 | new_iy = fixed2int(cr->y) - base; | 
|---|
| 501 | if (new_iy != iy) { | 
|---|
| 502 | cursor_output(eb, rev, iy); | 
|---|
| 503 | cr->left = x; | 
|---|
| 504 | cr->right = x; | 
|---|
| 505 | } else { | 
|---|
| 506 | if (x < cr->left) | 
|---|
| 507 | cr->left = x; | 
|---|
| 508 | if (x > cr->right) | 
|---|
| 509 | cr->right = x; | 
|---|
| 510 | } | 
|---|
| 511 | } | 
|---|
| 512 |  | 
|---|
| 513 | /* Step the cursor in y, never by enough to cross a scanline. */ | 
|---|
| 514 | static inline void | 
|---|
| 515 | cursor_never_step_vertical(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 516 | { | 
|---|
| 517 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 518 |  | 
|---|
| 519 | assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); | 
|---|
| 520 |  | 
|---|
| 521 | cr->y += dy; | 
|---|
| 522 | } | 
|---|
| 523 |  | 
|---|
| 524 | /* Step the cursor in y, never by enough to cross a scanline, | 
|---|
| 525 | * knowing that we are moving left, and that the right edge | 
|---|
| 526 | * has already been accounted for. */ | 
|---|
| 527 | static inline void | 
|---|
| 528 | cursor_never_step_left(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 529 | { | 
|---|
| 530 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 531 |  | 
|---|
| 532 | assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); | 
|---|
| 533 |  | 
|---|
| 534 | if (x < cr->left) | 
|---|
| 535 | cr->left = x; | 
|---|
| 536 | cr->y += dy; | 
|---|
| 537 | } | 
|---|
| 538 |  | 
|---|
| 539 | /* Step the cursor in y, never by enough to cross a scanline, | 
|---|
| 540 | * knowing that we are moving right, and that the left edge | 
|---|
| 541 | * has already been accounted for. */ | 
|---|
| 542 | static inline void | 
|---|
| 543 | cursor_never_step_right(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 544 | { | 
|---|
| 545 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 546 |  | 
|---|
| 547 | assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); | 
|---|
| 548 |  | 
|---|
| 549 | if (x > cr->right) | 
|---|
| 550 | cr->right = x; | 
|---|
| 551 | cr->y += dy; | 
|---|
| 552 | } | 
|---|
| 553 |  | 
|---|
| 554 | /* Step the cursor in y, always by enough to cross a scanline. */ | 
|---|
| 555 | static inline void | 
|---|
| 556 | cursor_always_step(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 557 | { | 
|---|
| 558 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 559 | int base = eb->super.clip.y0; | 
|---|
| 560 | int iy = fixed2int(cr->y) - base; | 
|---|
| 561 |  | 
|---|
| 562 | cursor_output(eb, rev, iy); | 
|---|
| 563 | cr->y += dy; | 
|---|
| 564 | cr->left = x; | 
|---|
| 565 | cr->right = x; | 
|---|
| 566 | } | 
|---|
| 567 |  | 
|---|
| 568 | /* Step the cursor in y, always by enough to cross a scanline, as | 
|---|
| 569 | * part of a vertical line, knowing that we are moving from a | 
|---|
| 570 | * position guaranteed to be in the valid y range. */ | 
|---|
| 571 | static inline void | 
|---|
| 572 | cursor_always_step_inrange_vertical(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 573 | { | 
|---|
| 574 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 575 | int base = eb->super.clip.y0; | 
|---|
| 576 | int iy = fixed2int(cr->y) - base; | 
|---|
| 577 |  | 
|---|
| 578 | cursor_output(eb, rev, iy); | 
|---|
| 579 | cr->y += dy; | 
|---|
| 580 | } | 
|---|
| 581 |  | 
|---|
| 582 | /* Step the cursor in y, always by enough to cross a scanline, as | 
|---|
| 583 | * part of a left moving line, knowing that we are moving from a | 
|---|
| 584 | * position guaranteed to be in the valid y range. */ | 
|---|
| 585 | static inline void | 
|---|
| 586 | cursor_always_inrange_step_left(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 587 | { | 
|---|
| 588 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 589 | int base = eb->super.clip.y0; | 
|---|
| 590 | int iy = fixed2int(cr->y) - base; | 
|---|
| 591 |  | 
|---|
| 592 | cr->y += dy; | 
|---|
| 593 | cursor_output_inrange(eb, rev, iy); | 
|---|
| 594 | cr->right = x; | 
|---|
| 595 | } | 
|---|
| 596 |  | 
|---|
| 597 | /* Step the cursor in y, always by enough to cross a scanline, as | 
|---|
| 598 | * part of a right moving line, knowing that we are moving from a | 
|---|
| 599 | * position guaranteed to be in the valid y range. */ | 
|---|
| 600 | static inline void | 
|---|
| 601 | cursor_always_inrange_step_right(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x) | 
|---|
| 602 | { | 
|---|
| 603 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 604 | int base = eb->super.clip.y0; | 
|---|
| 605 | int iy = fixed2int(cr->y) - base; | 
|---|
| 606 |  | 
|---|
| 607 | cr->y += dy; | 
|---|
| 608 | cursor_output_inrange(eb, rev, iy); | 
|---|
| 609 | cr->left = x; | 
|---|
| 610 | } | 
|---|
| 611 |  | 
|---|
| 612 | static inline void cursor_init(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed y, fixed x) | 
|---|
| 613 | { | 
|---|
| 614 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 615 |  | 
|---|
| 616 | assert(y >= int2fixed(eb->super.clip.y0) && y <= int2fixed(eb->super.clip.y1)); | 
|---|
| 617 |  | 
|---|
| 618 | cr->y = y; | 
|---|
| 619 | cr->left = x; | 
|---|
| 620 | cr->right = x; | 
|---|
| 621 | cr->d = DIRN_UNSET; | 
|---|
| 622 | } | 
|---|
| 623 |  | 
|---|
| 624 | static inline void cursor_left_merge(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x) | 
|---|
| 625 | { | 
|---|
| 626 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 627 |  | 
|---|
| 628 | if (x < cr->left) | 
|---|
| 629 | cr->left = x; | 
|---|
| 630 | } | 
|---|
| 631 |  | 
|---|
| 632 | static inline void cursor_left(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x) | 
|---|
| 633 | { | 
|---|
| 634 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 635 |  | 
|---|
| 636 | cr->left = x; | 
|---|
| 637 | } | 
|---|
| 638 |  | 
|---|
| 639 | static inline void cursor_right_merge(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x) | 
|---|
| 640 | { | 
|---|
| 641 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 642 |  | 
|---|
| 643 | if (x > cr->right) | 
|---|
| 644 | cr->right = x; | 
|---|
| 645 | } | 
|---|
| 646 |  | 
|---|
| 647 | static inline void cursor_right(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x) | 
|---|
| 648 | { | 
|---|
| 649 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 650 |  | 
|---|
| 651 | cr->right = x; | 
|---|
| 652 | } | 
|---|
| 653 |  | 
|---|
| 654 | static inline void cursor_down(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x) | 
|---|
| 655 | { | 
|---|
| 656 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 657 | int base = eb->super.clip.y0; | 
|---|
| 658 |  | 
|---|
| 659 | if (cr->d == DIRN_UP) | 
|---|
| 660 | { | 
|---|
| 661 | cursor_output(eb, rev, fixed2int(cr->y) - base); | 
|---|
| 662 | cr->left = x; | 
|---|
| 663 | cr->right = x; | 
|---|
| 664 | } | 
|---|
| 665 | cr->d = DIRN_DOWN; | 
|---|
| 666 | } | 
|---|
| 667 |  | 
|---|
| 668 | static inline void cursor_up(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x) | 
|---|
| 669 | { | 
|---|
| 670 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 671 | int base = eb->super.clip.y0; | 
|---|
| 672 |  | 
|---|
| 673 | if (cr->d == DIRN_DOWN) | 
|---|
| 674 | { | 
|---|
| 675 | cursor_output(eb, rev, fixed2int(cr->y) - base); | 
|---|
| 676 | cr->left = x; | 
|---|
| 677 | cr->right = x; | 
|---|
| 678 | } | 
|---|
| 679 | cr->d = DIRN_UP; | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | static inline int dirns_match(int d0, int d1) | 
|---|
| 683 | { | 
|---|
| 684 | return d0 == d1 || d0 == DIRN_UNSET || d1 == DIRN_UNSET; | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | static inline int dirn_flip(int d) | 
|---|
| 688 | { | 
|---|
| 689 | return d < 0 ? d : d^1; | 
|---|
| 690 | } | 
|---|
| 691 |  | 
|---|
| 692 | static inline int dirns_merge(int d0, int d1) | 
|---|
| 693 | { | 
|---|
| 694 | if (d0 == DIRN_UNSET) | 
|---|
| 695 | return d1; | 
|---|
| 696 | assert(dirns_match(d0, d1)); | 
|---|
| 697 | return d0; | 
|---|
| 698 | } | 
|---|
| 699 |  | 
|---|
| 700 | static void | 
|---|
| 701 | cursor_flush(fz_edgebuffer * FZ_RESTRICT eb) | 
|---|
| 702 | { | 
|---|
| 703 | int base = eb->super.clip.y0; | 
|---|
| 704 | int iy0, iy1, iy2; | 
|---|
| 705 | cursor_t * FZ_RESTRICT cr0 = &eb->cursor[0]; | 
|---|
| 706 | cursor_t * FZ_RESTRICT cr1 = &eb->cursor[1]; | 
|---|
| 707 | cursor_t * FZ_RESTRICT cr2 = &eb->cursor[2]; | 
|---|
| 708 |  | 
|---|
| 709 | if (cr0->unset) | 
|---|
| 710 | { | 
|---|
| 711 | assert(cr1->unset && cr2->unset); | 
|---|
| 712 | return; | 
|---|
| 713 | } | 
|---|
| 714 |  | 
|---|
| 715 | iy0 = fixed2int(cr0->y) - base; | 
|---|
| 716 | iy1 = fixed2int(cr1->y) - base; | 
|---|
| 717 | if (!cr2->unset) | 
|---|
| 718 | { | 
|---|
| 719 | assert(!cr1->unset); | 
|---|
| 720 | iy2 = fixed2int(cr2->y) - base; | 
|---|
| 721 | /* Try to merge the end of cursor 0 with the end of cursor 1 */ | 
|---|
| 722 | if (iy0 == iy1 && dirns_match(cr0->d, dirn_flip(cr1->d))) | 
|---|
| 723 | { | 
|---|
| 724 | /* Succeeded! Just one to output. */ | 
|---|
| 725 | cr0->d = dirns_merge(cr0->d, dirn_flip(cr1->d)); | 
|---|
| 726 | if (cr0->left > cr1->left) | 
|---|
| 727 | cr0->left = cr1->left; | 
|---|
| 728 | if (cr0->right < cr1->right) | 
|---|
| 729 | cr0->right = cr1->right; | 
|---|
| 730 | cr1->unset = 1; /* Stop us outputting cursor 1 later */ | 
|---|
| 731 | } | 
|---|
| 732 |  | 
|---|
| 733 | /* Try to merge the end of cursor 2 with the start of cursor 0 */ | 
|---|
| 734 | if (cr0->saved) | 
|---|
| 735 | { | 
|---|
| 736 | if (cr0->save_iy == iy2 && dirns_match(cr0->save_d, cr2->d)) | 
|---|
| 737 | { | 
|---|
| 738 | cr0->save_d = dirns_merge(cr0->save_d, cr2->d); | 
|---|
| 739 | if (cr0->save_left > cr2->left) | 
|---|
| 740 | cr0->save_left = cr2->left; | 
|---|
| 741 | if (cr0->save_right > cr2->right) | 
|---|
| 742 | cr0->save_right = cr2->right; | 
|---|
| 743 | cr2->unset = 1; /* Stop us outputting cursor 2 later */ | 
|---|
| 744 | } | 
|---|
| 745 | } | 
|---|
| 746 | else | 
|---|
| 747 | { | 
|---|
| 748 | /* Maybe cursor 0 never moved from the original pixel */ | 
|---|
| 749 | if (iy0 == iy2 && dirns_match(cr0->d, cr2->d)) | 
|---|
| 750 | { | 
|---|
| 751 | cr0->d = dirns_merge(cr0->d, cr2->d); | 
|---|
| 752 | if (cr0->left > cr2->left) | 
|---|
| 753 | cr0->left = cr2->left; | 
|---|
| 754 | if (cr0->right > cr2->right) | 
|---|
| 755 | cr0->right = cr2->right; | 
|---|
| 756 | cr2->unset = 1; /* Stop us outputting cursor 2 later */ | 
|---|
| 757 | } | 
|---|
| 758 | } | 
|---|
| 759 |  | 
|---|
| 760 | /* Try to merge the start of cursor 2 with the start of cursor 1 */ | 
|---|
| 761 | if (cr1->saved) | 
|---|
| 762 | { | 
|---|
| 763 | if (cr2->saved) | 
|---|
| 764 | { | 
|---|
| 765 | if (cr2->save_iy == cr1->save_iy && dirns_match(cr2->save_d, dirn_flip(cr1->save_d))) | 
|---|
| 766 | { | 
|---|
| 767 | cr2->save_d = dirns_merge(cr2->save_d, dirn_flip(cr1->save_d)); | 
|---|
| 768 | if (cr2->save_left > cr1->save_left) | 
|---|
| 769 | cr2->save_left = cr1->save_left; | 
|---|
| 770 | if (cr2->save_right > cr1->save_right) | 
|---|
| 771 | cr2->save_right = cr1->save_right; | 
|---|
| 772 | cr1->saved = 0; /* Don't output cr1->saved again later */ | 
|---|
| 773 | } | 
|---|
| 774 | } | 
|---|
| 775 | else if (!cr2->unset) | 
|---|
| 776 | { | 
|---|
| 777 | /* Maybe cursor 2 never moved from the original pixel */ | 
|---|
| 778 | if (iy2 == cr1->save_iy && dirns_match(cr2->d, dirn_flip(cr1->save_d))) | 
|---|
| 779 | { | 
|---|
| 780 | cr2->d = dirns_merge(cr2->d, dirn_flip(cr1->save_d)); | 
|---|
| 781 | if (cr2->left > cr1->save_left) | 
|---|
| 782 | cr2->left = cr1->save_left; | 
|---|
| 783 | if (cr2->right > cr1->save_right) | 
|---|
| 784 | cr2->right = cr1->save_right; | 
|---|
| 785 | cr1->saved = 0; /* Don't output cr1->saved again later */ | 
|---|
| 786 | } | 
|---|
| 787 | } | 
|---|
| 788 | } | 
|---|
| 789 | else if (!cr1->unset) | 
|---|
| 790 | { | 
|---|
| 791 | /* Cursor 1 might not have moved from the original pixel, hence nothing saved */ | 
|---|
| 792 | if (cr2->saved) | 
|---|
| 793 | { | 
|---|
| 794 | if (cr2->save_iy == iy1 && dirns_match(cr2->save_d, dirn_flip(cr1->d))) | 
|---|
| 795 | { | 
|---|
| 796 | cr2->save_d = dirns_merge(cr2->save_d, dirn_flip(cr1->d)); | 
|---|
| 797 | if (cr2->save_left > cr1->left) | 
|---|
| 798 | cr2->save_left = cr1->left; | 
|---|
| 799 | if (cr2->save_right > cr1->right) | 
|---|
| 800 | cr2->save_right = cr1->right; | 
|---|
| 801 | cr1->unset = 1; /* Stop us outputting cursor 1 later */ | 
|---|
| 802 | } | 
|---|
| 803 | } | 
|---|
| 804 | else if (!cr2->unset) | 
|---|
| 805 | { | 
|---|
| 806 | /* Maybe cursor 2 never moved from the original pixel */ | 
|---|
| 807 | if (iy2 == iy1 && dirns_match(cr2->d, dirn_flip(cr1->d))) | 
|---|
| 808 | { | 
|---|
| 809 | cr2->d = dirns_merge(cr2->d, dirn_flip(cr1->d)); | 
|---|
| 810 | if (cr2->left > cr1->left) | 
|---|
| 811 | cr2->left = cr1->left; | 
|---|
| 812 | if (cr2->right > cr1->right) | 
|---|
| 813 | cr2->right = cr1->right; | 
|---|
| 814 | cr1->unset = 1; /* Stop us outputting cursor 1 later */ | 
|---|
| 815 | } | 
|---|
| 816 | } | 
|---|
| 817 | } | 
|---|
| 818 | else | 
|---|
| 819 | { | 
|---|
| 820 | /* Cursor 1 might not have moved from the original pixel, hence nothing saved, | 
|---|
| 821 | * AND we might have merged it with cursor 0 already! */ | 
|---|
| 822 | if (cr2->saved) | 
|---|
| 823 | { | 
|---|
| 824 | if (iy0 == cr2->save_iy && dirns_match(cr0->d, cr2->save_d)) | 
|---|
| 825 | { | 
|---|
| 826 | cr0->d = dirns_merge(cr0->d, cr2->save_d); | 
|---|
| 827 | if (cr0->left > cr2->save_left) | 
|---|
| 828 | cr0->left = cr2->save_left; | 
|---|
| 829 | if (cr0->right > cr2->save_right) | 
|---|
| 830 | cr0->right = cr2->save_right; | 
|---|
| 831 | cr2->saved = 0; /* Stop us outputting saved cursor 2 later */ | 
|---|
| 832 | } | 
|---|
| 833 | } | 
|---|
| 834 | else if (!cr2->unset) | 
|---|
| 835 | { | 
|---|
| 836 | /* Maybe cursor 2 never moved from the original pixel */ | 
|---|
| 837 | if (iy0 == iy2 && dirns_match(cr0->d, cr2->d)) | 
|---|
| 838 | { | 
|---|
| 839 | cr0->d = dirns_merge(cr0->d, cr2->d); | 
|---|
| 840 | if (cr0->left > cr2->left) | 
|---|
| 841 | cr0->left = cr2->left; | 
|---|
| 842 | if (cr0->right > cr2->right) | 
|---|
| 843 | cr0->right = cr2->right; | 
|---|
| 844 | cr2->unset = 1; /* Stop us outputting cursor 2 later */ | 
|---|
| 845 | } | 
|---|
| 846 | } | 
|---|
| 847 | } | 
|---|
| 848 | } | 
|---|
| 849 | else | 
|---|
| 850 | { | 
|---|
| 851 | /* Try to merge the end of cursor 0 with the start of cursor 0 */ | 
|---|
| 852 | if (cr0->saved) | 
|---|
| 853 | { | 
|---|
| 854 | if (iy0 == cr0->save_iy && dirns_match(cr0->d, cr0->save_d)) | 
|---|
| 855 | { | 
|---|
| 856 | cr0->d = dirns_merge(cr0->d, cr0->save_d); | 
|---|
| 857 | if (cr0->left > cr0->save_left) | 
|---|
| 858 | cr0->left = cr0->save_left; | 
|---|
| 859 | if (cr0->right > cr0->save_right) | 
|---|
| 860 | cr0->right = cr0->save_right; | 
|---|
| 861 | cr0->saved = 0; /* Stop us outputting saved cursor 0 later */ | 
|---|
| 862 | } | 
|---|
| 863 | } | 
|---|
| 864 |  | 
|---|
| 865 | if (!cr1->unset) | 
|---|
| 866 | { | 
|---|
| 867 | /* Try to merge the end of cursor 1 with the start of cursor 1 */ | 
|---|
| 868 | if (cr1->saved) | 
|---|
| 869 | { | 
|---|
| 870 | if (iy1 == cr1->save_iy && dirns_match(cr1->d, cr1->save_d)) | 
|---|
| 871 | { | 
|---|
| 872 | cr1->d = dirns_merge(cr1->d, cr1->save_d); | 
|---|
| 873 | if (cr1->left > cr1->save_left) | 
|---|
| 874 | cr1->left = cr1->save_left; | 
|---|
| 875 | if (cr1->right > cr1->save_right) | 
|---|
| 876 | cr1->right = cr1->save_right; | 
|---|
| 877 | cr1->saved = 0; /* Stop us outputting saved cursor 1 later */ | 
|---|
| 878 | } | 
|---|
| 879 | } | 
|---|
| 880 | } | 
|---|
| 881 | } | 
|---|
| 882 |  | 
|---|
| 883 | if (!cr0->unset) | 
|---|
| 884 | cursor_output(eb, 0, iy0); | 
|---|
| 885 | if (cr0->saved) | 
|---|
| 886 | { | 
|---|
| 887 | cr0->left = cr0->save_left; | 
|---|
| 888 | cr0->right = cr0->save_right; | 
|---|
| 889 | cr0->d = cr0->save_d; | 
|---|
| 890 | cursor_output(eb, 0, cr0->save_iy); | 
|---|
| 891 | } | 
|---|
| 892 | if (!cr1->unset) | 
|---|
| 893 | cursor_output(eb, 1, iy1); | 
|---|
| 894 | if (cr1->saved) | 
|---|
| 895 | { | 
|---|
| 896 | cr1->left = cr1->save_left; | 
|---|
| 897 | cr1->right = cr1->save_right; | 
|---|
| 898 | cr1->d = cr1->save_d; | 
|---|
| 899 | cursor_output(eb, 1, cr1->save_iy); | 
|---|
| 900 | } | 
|---|
| 901 | if (!cr2->unset) | 
|---|
| 902 | cursor_output(eb, 2, iy2); | 
|---|
| 903 | if (cr2->saved) | 
|---|
| 904 | { | 
|---|
| 905 | cr2->left = cr2->save_left; | 
|---|
| 906 | cr2->right = cr2->save_right; | 
|---|
| 907 | cr2->d = cr2->save_d; | 
|---|
| 908 | cursor_output(eb, 2, cr2->save_iy); | 
|---|
| 909 | } | 
|---|
| 910 | } | 
|---|
| 911 |  | 
|---|
| 912 | static void do_mark_line_app(fz_context *ctx, fz_edgebuffer *eb, fixed sx, fixed sy, fixed ex, fixed ey, int rev) | 
|---|
| 913 | { | 
|---|
| 914 | int base_y = eb->super.clip.y0; | 
|---|
| 915 | int height = eb->super.clip.y1 - eb->super.clip.y0; | 
|---|
| 916 | int isy, iey; | 
|---|
| 917 | fixed y_steps; | 
|---|
| 918 | fixed save_sy = sy; | 
|---|
| 919 | fixed save_ex = ex; | 
|---|
| 920 | fixed save_ey = ey; | 
|---|
| 921 | int truncated; | 
|---|
| 922 | cursor_t * FZ_RESTRICT cr = &eb->cursor[rev]; | 
|---|
| 923 |  | 
|---|
| 924 | if (cr->unset) | 
|---|
| 925 | cr->y = sy, cr->left = sx, cr->right = sx, cr->unset = 0; | 
|---|
| 926 |  | 
|---|
| 927 | /* Floating point inaccuracies can cause these not *quite* to be true. */ | 
|---|
| 928 | assert(cr->y == sy && cr->left <= sx && cr->right >= sx && cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); | 
|---|
| 929 | sy = cr->y; | 
|---|
| 930 | if (cr->left > sx) | 
|---|
| 931 | sx = cr->left; | 
|---|
| 932 | else if (cr->right < sx) | 
|---|
| 933 | sx = cr->right; | 
|---|
| 934 |  | 
|---|
| 935 | if (sx == ex && sy == ey) | 
|---|
| 936 | return; | 
|---|
| 937 |  | 
|---|
| 938 | isy = fixed2int(sy) - base_y; | 
|---|
| 939 | iey = fixed2int(ey) - base_y; | 
|---|
| 940 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 941 | if (debugging_scan_converter) | 
|---|
| 942 | fz_write_printf(ctx, fz_stderr(ctx), "Marking line (app) from %x,%x to %x,%x (%x,%x) %d\n", sx, sy, ex, ey, isy, iey, rev); | 
|---|
| 943 | #endif | 
|---|
| 944 |  | 
|---|
| 945 | if (isy < iey) { | 
|---|
| 946 | /* Rising line */ | 
|---|
| 947 | if (iey < 0 || isy >= height) { | 
|---|
| 948 | /* All line is outside. */ | 
|---|
| 949 | cr->y = ey; | 
|---|
| 950 | cr->left = ex; | 
|---|
| 951 | cr->right = ex; | 
|---|
| 952 | cr->can_save = 0; | 
|---|
| 953 | return; | 
|---|
| 954 | } | 
|---|
| 955 | if (isy < 0) { | 
|---|
| 956 | /* Move sy up */ | 
|---|
| 957 | int y = ey - sy; | 
|---|
| 958 | int new_sy = int2fixed(base_y); | 
|---|
| 959 | int dy = new_sy - sy; | 
|---|
| 960 | sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); | 
|---|
| 961 | sy = new_sy; | 
|---|
| 962 | cursor_init(eb, rev, sy, sx); | 
|---|
| 963 | isy = 0; | 
|---|
| 964 | } | 
|---|
| 965 | truncated = iey > height; | 
|---|
| 966 | if (truncated) { | 
|---|
| 967 | /* Move ey down */ | 
|---|
| 968 | int y = ey - sy; | 
|---|
| 969 | int new_ey = int2fixed(base_y + height); | 
|---|
| 970 | int dy = ey - new_ey; | 
|---|
| 971 | save_ex = ex; | 
|---|
| 972 | save_ey = ey; | 
|---|
| 973 | ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); | 
|---|
| 974 | ey = new_ey; | 
|---|
| 975 | iey = height; | 
|---|
| 976 | } | 
|---|
| 977 | } else { | 
|---|
| 978 | /* Falling line */ | 
|---|
| 979 | if (isy < 0 || iey >= height) { | 
|---|
| 980 | /* All line is outside. */ | 
|---|
| 981 | cr->y = ey; | 
|---|
| 982 | cr->left = ex; | 
|---|
| 983 | cr->right = ex; | 
|---|
| 984 | cr->can_save = 0; | 
|---|
| 985 | return; | 
|---|
| 986 | } | 
|---|
| 987 | truncated = iey < 0; | 
|---|
| 988 | if (truncated) { | 
|---|
| 989 | /* Move ey up */ | 
|---|
| 990 | int y = ey - sy; | 
|---|
| 991 | int new_ey = int2fixed(base_y); | 
|---|
| 992 | int dy = ey - new_ey; | 
|---|
| 993 | ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); | 
|---|
| 994 | ey = new_ey; | 
|---|
| 995 | iey = 0; | 
|---|
| 996 | } | 
|---|
| 997 | if (isy >= height) { | 
|---|
| 998 | /* Move sy down */ | 
|---|
| 999 | int y = ey - sy; | 
|---|
| 1000 | if (y) { | 
|---|
| 1001 | int new_sy = int2fixed(base_y + height); | 
|---|
| 1002 | int dy = new_sy - sy; | 
|---|
| 1003 | sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); | 
|---|
| 1004 | sy = new_sy; | 
|---|
| 1005 | cursor_init(eb, rev, sy, sx); | 
|---|
| 1006 | isy = height; | 
|---|
| 1007 | } | 
|---|
| 1008 | } | 
|---|
| 1009 | } | 
|---|
| 1010 |  | 
|---|
| 1011 | assert(cr->left <= sx); | 
|---|
| 1012 | assert(cr->right >= sx); | 
|---|
| 1013 | assert(cr->y == sy); | 
|---|
| 1014 |  | 
|---|
| 1015 | /* A note: The code below used to be of the form: | 
|---|
| 1016 | *   if (isy == iey)   ... deal with horizontal lines | 
|---|
| 1017 | *   else if (ey > sy) { | 
|---|
| 1018 | *	 fixed y_steps = ey - sy; | 
|---|
| 1019 | *	  ... deal with rising lines ... | 
|---|
| 1020 | *   } else { | 
|---|
| 1021 | *	 fixed y_steps = ey - sy; | 
|---|
| 1022 | *	 ... deal with falling lines | 
|---|
| 1023 | *   } | 
|---|
| 1024 | * but that lead to problems, for instance, an example seen | 
|---|
| 1025 | * has sx=2aa8e, sy=8aee7, ex=7ffc1686, ey=8003e97a. | 
|---|
| 1026 | * Thus isy=84f, iey=ff80038a. We can see that ey < sy, but | 
|---|
| 1027 | * sy - ey < 0! | 
|---|
| 1028 | * We therefore rejig our code so that the choice between | 
|---|
| 1029 | * cases is done based on the sign of y_steps rather than | 
|---|
| 1030 | * the relative size of ey and sy. | 
|---|
| 1031 | */ | 
|---|
| 1032 |  | 
|---|
| 1033 | /* First, deal with lines that don't change scanline. | 
|---|
| 1034 | * This accommodates horizontal lines. */ | 
|---|
| 1035 | if (isy == iey) { | 
|---|
| 1036 | if (save_sy == save_ey) { | 
|---|
| 1037 | /* Horizontal line. Don't change cr->d, don't flush. */ | 
|---|
| 1038 | } else if (save_sy > save_ey) { | 
|---|
| 1039 | /* Falling line, flush if previous was rising */ | 
|---|
| 1040 | cursor_down(eb, rev, sx); | 
|---|
| 1041 | } else { | 
|---|
| 1042 | /* Rising line, flush if previous was falling */ | 
|---|
| 1043 | cursor_up(eb, rev, sx); | 
|---|
| 1044 | } | 
|---|
| 1045 | if (sx <= ex) { | 
|---|
| 1046 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1047 | cursor_right_merge(eb, rev, ex); | 
|---|
| 1048 | } else { | 
|---|
| 1049 | cursor_left_merge(eb, rev, ex); | 
|---|
| 1050 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1051 | } | 
|---|
| 1052 | cr->y = ey; | 
|---|
| 1053 | if (sy > save_ey) | 
|---|
| 1054 | goto endFalling; | 
|---|
| 1055 | } else if ((y_steps = ey - sy) > 0) { | 
|---|
| 1056 | /* We want to change from sy to ey, which are guaranteed to be on | 
|---|
| 1057 | * different scanlines. We do this in 3 phases. | 
|---|
| 1058 | * Phase 1 gets us from sy to the next scanline boundary. | 
|---|
| 1059 | * Phase 2 gets us all the way to the last scanline boundary. | 
|---|
| 1060 | * Phase 3 gets us from the last scanline boundary to ey. | 
|---|
| 1061 | */ | 
|---|
| 1062 | /* We want to change from sy to ey, which are guaranteed to be on | 
|---|
| 1063 | * different scanlines. We do this in 3 phases. | 
|---|
| 1064 | * Phase 1 gets us from sy to the next scanline boundary. (We may exit after phase 1). | 
|---|
| 1065 | * Phase 2 gets us all the way to the last scanline boundary. (This may be a null operation) | 
|---|
| 1066 | * Phase 3 gets us from the last scanline boundary to ey. (We are guaranteed to have output the cursor at least once before phase 3). | 
|---|
| 1067 | */ | 
|---|
| 1068 | int phase1_y_steps = (-sy) & (fixed_1 - 1); | 
|---|
| 1069 | int phase3_y_steps = ey & (fixed_1 - 1); | 
|---|
| 1070 |  | 
|---|
| 1071 | cursor_up(eb, rev, sx); | 
|---|
| 1072 |  | 
|---|
| 1073 | if (sx == ex) { | 
|---|
| 1074 | /* Vertical line. (Rising) */ | 
|---|
| 1075 |  | 
|---|
| 1076 | /* Phase 1: */ | 
|---|
| 1077 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1078 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1079 | if (phase1_y_steps) { | 
|---|
| 1080 | /* If phase 1 will move us into a new scanline, then we must | 
|---|
| 1081 | * flush it before we move. */ | 
|---|
| 1082 | cursor_step(eb, rev, phase1_y_steps, sx); | 
|---|
| 1083 | sy += phase1_y_steps; | 
|---|
| 1084 | y_steps -= phase1_y_steps; | 
|---|
| 1085 | if (y_steps == 0) | 
|---|
| 1086 | goto end; | 
|---|
| 1087 | } | 
|---|
| 1088 |  | 
|---|
| 1089 | /* Phase 3: precalculation */ | 
|---|
| 1090 | y_steps -= phase3_y_steps; | 
|---|
| 1091 |  | 
|---|
| 1092 | /* Phase 2: */ | 
|---|
| 1093 | y_steps = fixed2int(y_steps); | 
|---|
| 1094 | assert(y_steps >= 0); | 
|---|
| 1095 | if (y_steps > 0) { | 
|---|
| 1096 | cursor_always_step(eb, rev, fixed_1, sx); | 
|---|
| 1097 | y_steps--; | 
|---|
| 1098 | while (y_steps) { | 
|---|
| 1099 | cursor_always_step_inrange_vertical(eb, rev, fixed_1, sx); | 
|---|
| 1100 | y_steps--; | 
|---|
| 1101 | } | 
|---|
| 1102 | } | 
|---|
| 1103 |  | 
|---|
| 1104 | /* Phase 3 */ | 
|---|
| 1105 | assert(cr->left == sx && cr->right == sx); | 
|---|
| 1106 | cr->y += phase3_y_steps; | 
|---|
| 1107 | } else if (sx < ex) { | 
|---|
| 1108 | /* Lines increasing in x. (Rightwards, rising) */ | 
|---|
| 1109 | int phase1_x_steps, phase3_x_steps; | 
|---|
| 1110 | fixed x_steps = ex - sx; | 
|---|
| 1111 |  | 
|---|
| 1112 | /* Phase 1: */ | 
|---|
| 1113 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1114 | if (phase1_y_steps) { | 
|---|
| 1115 | phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); | 
|---|
| 1116 | sx += phase1_x_steps; | 
|---|
| 1117 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1118 | x_steps -= phase1_x_steps; | 
|---|
| 1119 | cursor_step(eb, rev, phase1_y_steps, sx); | 
|---|
| 1120 | sy += phase1_y_steps; | 
|---|
| 1121 | y_steps -= phase1_y_steps; | 
|---|
| 1122 | if (y_steps == 0) | 
|---|
| 1123 | goto end; | 
|---|
| 1124 | } | 
|---|
| 1125 |  | 
|---|
| 1126 | /* Phase 3: precalculation */ | 
|---|
| 1127 | phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); | 
|---|
| 1128 | x_steps -= phase3_x_steps; | 
|---|
| 1129 | y_steps -= phase3_y_steps; | 
|---|
| 1130 | assert((y_steps & (fixed_1 - 1)) == 0); | 
|---|
| 1131 |  | 
|---|
| 1132 | /* Phase 2: */ | 
|---|
| 1133 | y_steps = fixed2int(y_steps); | 
|---|
| 1134 | assert(y_steps >= 0); | 
|---|
| 1135 | if (y_steps) { | 
|---|
| 1136 | /* We want to change sx by x_steps in y_steps steps. | 
|---|
| 1137 | * So each step, we add x_steps/y_steps to sx. That's x_inc + n_inc/y_steps. */ | 
|---|
| 1138 | int x_inc = x_steps/y_steps; | 
|---|
| 1139 | int n_inc = x_steps - (x_inc * y_steps); | 
|---|
| 1140 | int f = y_steps/2; | 
|---|
| 1141 | int d = y_steps; | 
|---|
| 1142 |  | 
|---|
| 1143 | /* Special casing the unset iteration, allows us to simplify | 
|---|
| 1144 | * the following loop. */ | 
|---|
| 1145 | sx += x_inc; | 
|---|
| 1146 | f -= n_inc; | 
|---|
| 1147 | if (f < 0) | 
|---|
| 1148 | f += d, sx++; | 
|---|
| 1149 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1150 | cursor_always_step(eb, rev, fixed_1, sx); | 
|---|
| 1151 | y_steps--; | 
|---|
| 1152 |  | 
|---|
| 1153 | while (y_steps) { | 
|---|
| 1154 | sx += x_inc; | 
|---|
| 1155 | f -= n_inc; | 
|---|
| 1156 | if (f < 0) | 
|---|
| 1157 | f += d, sx++; | 
|---|
| 1158 | cursor_right(eb, rev, sx); | 
|---|
| 1159 | cursor_always_inrange_step_right(eb, rev, fixed_1, sx); | 
|---|
| 1160 | y_steps--; | 
|---|
| 1161 | }; | 
|---|
| 1162 | } | 
|---|
| 1163 |  | 
|---|
| 1164 | /* Phase 3 */ | 
|---|
| 1165 | assert(cr->left <= ex && cr->right >= sx); | 
|---|
| 1166 | cursor_right(eb, rev, ex); | 
|---|
| 1167 | cr->y += phase3_y_steps; | 
|---|
| 1168 | } else { | 
|---|
| 1169 | /* Lines decreasing in x. (Leftwards, rising) */ | 
|---|
| 1170 | int phase1_x_steps, phase3_x_steps; | 
|---|
| 1171 | fixed x_steps = sx - ex; | 
|---|
| 1172 |  | 
|---|
| 1173 | /* Phase 1: */ | 
|---|
| 1174 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1175 | if (phase1_y_steps) { | 
|---|
| 1176 | phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); | 
|---|
| 1177 | x_steps -= phase1_x_steps; | 
|---|
| 1178 | sx -= phase1_x_steps; | 
|---|
| 1179 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1180 | cursor_step(eb, rev, phase1_y_steps, sx); | 
|---|
| 1181 | sy += phase1_y_steps; | 
|---|
| 1182 | y_steps -= phase1_y_steps; | 
|---|
| 1183 | if (y_steps == 0) | 
|---|
| 1184 | goto end; | 
|---|
| 1185 | } | 
|---|
| 1186 |  | 
|---|
| 1187 | /* Phase 3: precalculation */ | 
|---|
| 1188 | phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); | 
|---|
| 1189 | x_steps -= phase3_x_steps; | 
|---|
| 1190 | y_steps -= phase3_y_steps; | 
|---|
| 1191 | assert((y_steps & (fixed_1 - 1)) == 0); | 
|---|
| 1192 |  | 
|---|
| 1193 | /* Phase 2: */ | 
|---|
| 1194 | y_steps = fixed2int(y_steps); | 
|---|
| 1195 | assert(y_steps >= 0); | 
|---|
| 1196 | if (y_steps) { | 
|---|
| 1197 | /* We want to change sx by x_steps in y_steps steps. | 
|---|
| 1198 | * So each step, we sub x_steps/y_steps from sx. That's x_inc + n_inc/ey. */ | 
|---|
| 1199 | int x_inc = x_steps/y_steps; | 
|---|
| 1200 | int n_inc = x_steps - (x_inc * y_steps); | 
|---|
| 1201 | int f = y_steps/2; | 
|---|
| 1202 | int d = y_steps; | 
|---|
| 1203 |  | 
|---|
| 1204 | /* Special casing the unset iteration, allows us to simplify | 
|---|
| 1205 | * the following loop. */ | 
|---|
| 1206 | sx -= x_inc; | 
|---|
| 1207 | f -= n_inc; | 
|---|
| 1208 | if (f < 0) | 
|---|
| 1209 | f += d, sx--; | 
|---|
| 1210 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1211 | cursor_always_step(eb, rev, fixed_1, sx); | 
|---|
| 1212 | y_steps--; | 
|---|
| 1213 |  | 
|---|
| 1214 | while (y_steps) { | 
|---|
| 1215 | sx -= x_inc; | 
|---|
| 1216 | f -= n_inc; | 
|---|
| 1217 | if (f < 0) | 
|---|
| 1218 | f += d, sx--; | 
|---|
| 1219 | cursor_left(eb, rev, sx); | 
|---|
| 1220 | cursor_always_inrange_step_left(eb, rev, fixed_1, sx); | 
|---|
| 1221 | y_steps--; | 
|---|
| 1222 | } | 
|---|
| 1223 | } | 
|---|
| 1224 |  | 
|---|
| 1225 | /* Phase 3 */ | 
|---|
| 1226 | assert(cr->right >= ex && cr->left <= sx); | 
|---|
| 1227 | cursor_left(eb, rev, ex); | 
|---|
| 1228 | cr->y += phase3_y_steps; | 
|---|
| 1229 | } | 
|---|
| 1230 | } else { | 
|---|
| 1231 | /* So lines decreasing in y. */ | 
|---|
| 1232 | /* We want to change from sy to ey, which are guaranteed to be on | 
|---|
| 1233 | * different scanlines. We do this in 3 phases. | 
|---|
| 1234 | * Phase 1 gets us from sy to the next scanline boundary. This never causes an output. | 
|---|
| 1235 | * Phase 2 gets us all the way to the last scanline boundary. This is guaranteed to cause an output. | 
|---|
| 1236 | * Phase 3 gets us from the last scanline boundary to ey. We are guaranteed to have outputted by now. | 
|---|
| 1237 | */ | 
|---|
| 1238 | int phase1_y_steps = sy & (fixed_1 - 1); | 
|---|
| 1239 | int phase3_y_steps = (-ey) & (fixed_1 - 1); | 
|---|
| 1240 |  | 
|---|
| 1241 | y_steps = -y_steps; | 
|---|
| 1242 | /* Cope with the awkward 0x80000000 case. */ | 
|---|
| 1243 | if (y_steps < 0) | 
|---|
| 1244 | { | 
|---|
| 1245 | int mx, my; | 
|---|
| 1246 | mx = sx + ((ex-sx)>>1); | 
|---|
| 1247 | my = sy + ((ey-sy)>>1); | 
|---|
| 1248 | do_mark_line_app(ctx, eb, sx, sy, mx, my, rev); | 
|---|
| 1249 | do_mark_line_app(ctx, eb, mx, my, ex, ey, rev); | 
|---|
| 1250 | return; | 
|---|
| 1251 | } | 
|---|
| 1252 |  | 
|---|
| 1253 | cursor_down(eb, rev, sx); | 
|---|
| 1254 |  | 
|---|
| 1255 | if (sx == ex) { | 
|---|
| 1256 | /* Vertical line. (Falling) */ | 
|---|
| 1257 |  | 
|---|
| 1258 | /* Phase 1: */ | 
|---|
| 1259 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1260 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1261 | if (phase1_y_steps) { | 
|---|
| 1262 | /* Phase 1 in a falling line never moves us into a new scanline. */ | 
|---|
| 1263 | cursor_never_step_vertical(eb, rev, -phase1_y_steps, sx); | 
|---|
| 1264 | sy -= phase1_y_steps; | 
|---|
| 1265 | y_steps -= phase1_y_steps; | 
|---|
| 1266 | if (y_steps == 0) | 
|---|
| 1267 | goto endFalling; | 
|---|
| 1268 | } | 
|---|
| 1269 |  | 
|---|
| 1270 | /* Phase 3: precalculation */ | 
|---|
| 1271 | y_steps -= phase3_y_steps; | 
|---|
| 1272 | assert((y_steps & (fixed_1 - 1)) == 0); | 
|---|
| 1273 |  | 
|---|
| 1274 | /* Phase 2: */ | 
|---|
| 1275 | y_steps = fixed2int(y_steps); | 
|---|
| 1276 | assert(y_steps >= 0); | 
|---|
| 1277 | if (y_steps) { | 
|---|
| 1278 | cursor_always_step(eb, rev, -fixed_1, sx); | 
|---|
| 1279 | y_steps--; | 
|---|
| 1280 | while (y_steps) { | 
|---|
| 1281 | cursor_always_step_inrange_vertical(eb, rev, -fixed_1, sx); | 
|---|
| 1282 | y_steps--; | 
|---|
| 1283 | } | 
|---|
| 1284 | } | 
|---|
| 1285 |  | 
|---|
| 1286 | /* Phase 3 */ | 
|---|
| 1287 | if (phase3_y_steps > 0) { | 
|---|
| 1288 | cursor_step(eb, rev, -phase3_y_steps, sx); | 
|---|
| 1289 | assert(cr->left == sx && cr->right == sx); | 
|---|
| 1290 | } | 
|---|
| 1291 | } else if (sx < ex) { | 
|---|
| 1292 | /* Lines increasing in x. (Rightwards, falling) */ | 
|---|
| 1293 | int phase1_x_steps, phase3_x_steps; | 
|---|
| 1294 | fixed x_steps = ex - sx; | 
|---|
| 1295 |  | 
|---|
| 1296 | /* Phase 1: */ | 
|---|
| 1297 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1298 | if (phase1_y_steps) { | 
|---|
| 1299 | phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); | 
|---|
| 1300 | x_steps -= phase1_x_steps; | 
|---|
| 1301 | sx += phase1_x_steps; | 
|---|
| 1302 | /* Phase 1 in a falling line never moves us into a new scanline. */ | 
|---|
| 1303 | cursor_never_step_right(eb, rev, -phase1_y_steps, sx); | 
|---|
| 1304 | sy -= phase1_y_steps; | 
|---|
| 1305 | y_steps -= phase1_y_steps; | 
|---|
| 1306 | if (y_steps == 0) | 
|---|
| 1307 | goto endFalling; | 
|---|
| 1308 | } else | 
|---|
| 1309 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1310 |  | 
|---|
| 1311 | /* Phase 3: precalculation */ | 
|---|
| 1312 | phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); | 
|---|
| 1313 | x_steps -= phase3_x_steps; | 
|---|
| 1314 | y_steps -= phase3_y_steps; | 
|---|
| 1315 | assert((y_steps & (fixed_1 - 1)) == 0); | 
|---|
| 1316 |  | 
|---|
| 1317 | /* Phase 2: */ | 
|---|
| 1318 | y_steps = fixed2int(y_steps); | 
|---|
| 1319 | assert(y_steps >= 0); | 
|---|
| 1320 | if (y_steps) { | 
|---|
| 1321 | /* We want to change sx by x_steps in y_steps steps. | 
|---|
| 1322 | * So each step, we add x_steps/y_steps to sx. That's x_inc + n_inc/ey. */ | 
|---|
| 1323 | int x_inc = x_steps/y_steps; | 
|---|
| 1324 | int n_inc = x_steps - (x_inc * y_steps); | 
|---|
| 1325 | int f = y_steps/2; | 
|---|
| 1326 | int d = y_steps; | 
|---|
| 1327 |  | 
|---|
| 1328 | cursor_always_step(eb, rev, -fixed_1, sx); | 
|---|
| 1329 | sx += x_inc; | 
|---|
| 1330 | f -= n_inc; | 
|---|
| 1331 | if (f < 0) | 
|---|
| 1332 | f += d, sx++; | 
|---|
| 1333 | cursor_right(eb, rev, sx); | 
|---|
| 1334 | y_steps--; | 
|---|
| 1335 |  | 
|---|
| 1336 | while (y_steps) { | 
|---|
| 1337 | cursor_always_inrange_step_right(eb, rev, -fixed_1, sx); | 
|---|
| 1338 | sx += x_inc; | 
|---|
| 1339 | f -= n_inc; | 
|---|
| 1340 | if (f < 0) | 
|---|
| 1341 | f += d, sx++; | 
|---|
| 1342 | cursor_right(eb, rev, sx); | 
|---|
| 1343 | y_steps--; | 
|---|
| 1344 | } | 
|---|
| 1345 | } | 
|---|
| 1346 |  | 
|---|
| 1347 | /* Phase 3 */ | 
|---|
| 1348 | if (phase3_y_steps > 0) { | 
|---|
| 1349 | cursor_step(eb, rev, -phase3_y_steps, sx); | 
|---|
| 1350 | cursor_right(eb, rev, ex); | 
|---|
| 1351 | assert(cr->left == sx && cr->right == ex); | 
|---|
| 1352 | } | 
|---|
| 1353 | } else { | 
|---|
| 1354 | /* Lines decreasing in x. (Falling) */ | 
|---|
| 1355 | int phase1_x_steps, phase3_x_steps; | 
|---|
| 1356 | fixed x_steps = sx - ex; | 
|---|
| 1357 |  | 
|---|
| 1358 | /* Phase 1: */ | 
|---|
| 1359 | cursor_right_merge(eb, rev, sx); | 
|---|
| 1360 | if (phase1_y_steps) { | 
|---|
| 1361 | phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); | 
|---|
| 1362 | x_steps -= phase1_x_steps; | 
|---|
| 1363 | sx -= phase1_x_steps; | 
|---|
| 1364 | /* Phase 1 in a falling line never moves us into a new scanline. */ | 
|---|
| 1365 | cursor_never_step_left(eb, rev, -phase1_y_steps, sx); | 
|---|
| 1366 | sy -= phase1_y_steps; | 
|---|
| 1367 | y_steps -= phase1_y_steps; | 
|---|
| 1368 | if (y_steps == 0) | 
|---|
| 1369 | goto endFalling; | 
|---|
| 1370 | } else | 
|---|
| 1371 | cursor_left_merge(eb, rev, sx); | 
|---|
| 1372 |  | 
|---|
| 1373 | /* Phase 3: precalculation */ | 
|---|
| 1374 | phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); | 
|---|
| 1375 | x_steps -= phase3_x_steps; | 
|---|
| 1376 | y_steps -= phase3_y_steps; | 
|---|
| 1377 | assert((y_steps & (fixed_1 - 1)) == 0); | 
|---|
| 1378 |  | 
|---|
| 1379 | /* Phase 2: */ | 
|---|
| 1380 | y_steps = fixed2int(y_steps); | 
|---|
| 1381 | assert(y_steps >= 0); | 
|---|
| 1382 | if (y_steps) { | 
|---|
| 1383 | /* We want to change sx by x_steps in y_steps steps. | 
|---|
| 1384 | * So each step, we sub x_steps/y_steps from sx. That's x_inc + n_inc/ey. */ | 
|---|
| 1385 | int x_inc = x_steps/y_steps; | 
|---|
| 1386 | int n_inc = x_steps - (x_inc * y_steps); | 
|---|
| 1387 | int f = y_steps/2; | 
|---|
| 1388 | int d = y_steps; | 
|---|
| 1389 |  | 
|---|
| 1390 | cursor_always_step(eb, rev, -fixed_1, sx); | 
|---|
| 1391 | sx -= x_inc; | 
|---|
| 1392 | f -= n_inc; | 
|---|
| 1393 | if (f < 0) | 
|---|
| 1394 | f += d, sx--; | 
|---|
| 1395 | cursor_left(eb, rev, sx); | 
|---|
| 1396 | y_steps--; | 
|---|
| 1397 |  | 
|---|
| 1398 | while (y_steps) { | 
|---|
| 1399 | cursor_always_inrange_step_left(eb, rev, -fixed_1, sx); | 
|---|
| 1400 | sx -= x_inc; | 
|---|
| 1401 | f -= n_inc; | 
|---|
| 1402 | if (f < 0) | 
|---|
| 1403 | f += d, sx--; | 
|---|
| 1404 | cursor_left(eb, rev, sx); | 
|---|
| 1405 | y_steps--; | 
|---|
| 1406 | } | 
|---|
| 1407 | } | 
|---|
| 1408 |  | 
|---|
| 1409 | /* Phase 3 */ | 
|---|
| 1410 | if (phase3_y_steps > 0) { | 
|---|
| 1411 | cursor_step(eb, rev, -phase3_y_steps, sx); | 
|---|
| 1412 | cursor_left(eb, rev, ex); | 
|---|
| 1413 | assert(cr->left == ex && cr->right == sx); | 
|---|
| 1414 | } | 
|---|
| 1415 | } | 
|---|
| 1416 | endFalling: | 
|---|
| 1417 | if (truncated) | 
|---|
| 1418 | cursor_output(eb, rev, fixed2int(cr->y) - base_y); | 
|---|
| 1419 | } | 
|---|
| 1420 |  | 
|---|
| 1421 | end: | 
|---|
| 1422 | if (truncated) { | 
|---|
| 1423 | cr->left = save_ex; | 
|---|
| 1424 | cr->right = save_ex; | 
|---|
| 1425 | cr->y = save_ey; | 
|---|
| 1426 | } | 
|---|
| 1427 | } | 
|---|
| 1428 |  | 
|---|
| 1429 | static void mark_line_app(fz_context *ctx, fz_edgebuffer *eb, fixed sx, fixed sy, fixed ex, fixed ey, int rev) | 
|---|
| 1430 | { | 
|---|
| 1431 | if (rev == 1) | 
|---|
| 1432 | { | 
|---|
| 1433 | fixed t; | 
|---|
| 1434 | t = sx, sx = ex, ex = t; | 
|---|
| 1435 | t = sy, sy = ey, ey = t; | 
|---|
| 1436 | } | 
|---|
| 1437 | do_mark_line_app(ctx, eb, sx, sy, ex, ey, rev); | 
|---|
| 1438 | } | 
|---|
| 1439 |  | 
|---|
| 1440 | static void fz_insert_edgebuffer_app(fz_context *ctx, fz_rasterizer *ras, float fsx, float fsy, float fex, float fey, int rev) | 
|---|
| 1441 | { | 
|---|
| 1442 | fz_edgebuffer *eb = (fz_edgebuffer *)ras; | 
|---|
| 1443 | fixed sx = float2fixed(fsx); | 
|---|
| 1444 | fixed sy = float2fixed(fsy); | 
|---|
| 1445 | fixed ex = float2fixed(fex); | 
|---|
| 1446 | fixed ey = float2fixed(fey); | 
|---|
| 1447 |  | 
|---|
| 1448 | if (fsx < fex) | 
|---|
| 1449 | { | 
|---|
| 1450 | if (fsx < eb->super.bbox.x0) eb->super.bbox.x0 = fsx; | 
|---|
| 1451 | if (fex > eb->super.bbox.x1) eb->super.bbox.x1 = fex; | 
|---|
| 1452 | } | 
|---|
| 1453 | else | 
|---|
| 1454 | { | 
|---|
| 1455 | if (fsx > eb->super.bbox.x1) eb->super.bbox.x1 = fsx; | 
|---|
| 1456 | if (fex < eb->super.bbox.x0) eb->super.bbox.x0 = fex; | 
|---|
| 1457 | } | 
|---|
| 1458 | if (fsy < fey) | 
|---|
| 1459 | { | 
|---|
| 1460 | if (fsy < eb->super.bbox.y0) eb->super.bbox.y0 = fsy; | 
|---|
| 1461 | if (fey > eb->super.bbox.y1) eb->super.bbox.y1 = fey; | 
|---|
| 1462 | } | 
|---|
| 1463 | else | 
|---|
| 1464 | { | 
|---|
| 1465 | if (fey < eb->super.bbox.y0) eb->super.bbox.y0 = fey; | 
|---|
| 1466 | if (fsy > eb->super.bbox.y1) eb->super.bbox.y1 = fsy; | 
|---|
| 1467 | } | 
|---|
| 1468 |  | 
|---|
| 1469 | mark_line_app(ctx, eb, sx, sy, ex, ey, rev); | 
|---|
| 1470 | } | 
|---|
| 1471 |  | 
|---|
| 1472 | static int intcmp(const void *a, const void *b) | 
|---|
| 1473 | { | 
|---|
| 1474 | return *((int*)a) - *((int *)b); | 
|---|
| 1475 | } | 
|---|
| 1476 |  | 
|---|
| 1477 | static void fz_convert_edgebuffer(fz_context *ctx, fz_rasterizer *ras, int eofill, const fz_irect *clip, fz_pixmap *pix, unsigned char *color, fz_overprint *eop) | 
|---|
| 1478 | { | 
|---|
| 1479 | fz_edgebuffer *eb = (fz_edgebuffer *)ras; | 
|---|
| 1480 | int scanlines = ras->clip.y1 - ras->clip.y0; | 
|---|
| 1481 | int i, n, a, pl, pr; | 
|---|
| 1482 | int *table = eb->table; | 
|---|
| 1483 | int *index = eb->index; | 
|---|
| 1484 | uint8_t *out; | 
|---|
| 1485 | fz_solid_color_painter_t *fn; | 
|---|
| 1486 |  | 
|---|
| 1487 | fn = fz_get_solid_color_painter(pix->n, color, pix->alpha, eop); | 
|---|
| 1488 | assert(fn); | 
|---|
| 1489 | if (fn == NULL) | 
|---|
| 1490 | return; | 
|---|
| 1491 |  | 
|---|
| 1492 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1493 | if (debugging_scan_converter) | 
|---|
| 1494 | { | 
|---|
| 1495 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1496 | fz_write_printf(ctx, err, "Before sort:\n"); | 
|---|
| 1497 | fz_edgebuffer_print(ctx, err, eb); | 
|---|
| 1498 | } | 
|---|
| 1499 | #endif | 
|---|
| 1500 |  | 
|---|
| 1501 | if (!eb->sorted) | 
|---|
| 1502 | { | 
|---|
| 1503 | eb->sorted = 1; | 
|---|
| 1504 | for (i = 0; i < scanlines; i++) | 
|---|
| 1505 | { | 
|---|
| 1506 | int *row = &table[index[i]]; | 
|---|
| 1507 | int rowlen = *row++; | 
|---|
| 1508 |  | 
|---|
| 1509 | /* Bubblesort short runs, qsort longer ones. */ | 
|---|
| 1510 | /* FIXME: Check "6" below */ | 
|---|
| 1511 | if (rowlen <= 6) { | 
|---|
| 1512 | int j, k; | 
|---|
| 1513 | for (j = 0; j < rowlen-1; j++) | 
|---|
| 1514 | { | 
|---|
| 1515 | int t = row[j]; | 
|---|
| 1516 | for (k = j+1; k < rowlen; k++) | 
|---|
| 1517 | { | 
|---|
| 1518 | int s = row[k]; | 
|---|
| 1519 | if (t > s) | 
|---|
| 1520 | row[k] = t, t = row[j] = s; | 
|---|
| 1521 | } | 
|---|
| 1522 | } | 
|---|
| 1523 | } else | 
|---|
| 1524 | qsort(row, rowlen, sizeof(int), intcmp); | 
|---|
| 1525 | } | 
|---|
| 1526 |  | 
|---|
| 1527 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1528 | if (debugging_scan_converter) | 
|---|
| 1529 | { | 
|---|
| 1530 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1531 | fz_write_printf(ctx, err, "Before filter: %s\n", eofill ? "EO": "NZ"); | 
|---|
| 1532 | fz_edgebuffer_print(ctx, err, eb); | 
|---|
| 1533 | } | 
|---|
| 1534 | #endif | 
|---|
| 1535 |  | 
|---|
| 1536 | for (i=0; i < scanlines; i++) { | 
|---|
| 1537 | int *row = &table[index[i]]; | 
|---|
| 1538 | int *rowstart = row; | 
|---|
| 1539 | int rowlen = *row++; | 
|---|
| 1540 | int *rowout = row; | 
|---|
| 1541 |  | 
|---|
| 1542 | while (rowlen > 0) | 
|---|
| 1543 | { | 
|---|
| 1544 | int left, right; | 
|---|
| 1545 |  | 
|---|
| 1546 | if (eofill) { | 
|---|
| 1547 | /* Even Odd */ | 
|---|
| 1548 | left  = (*row++)&~1; | 
|---|
| 1549 | right = (*row++)&~1; | 
|---|
| 1550 | rowlen -= 2; | 
|---|
| 1551 | } else { | 
|---|
| 1552 | /* Non-Zero */ | 
|---|
| 1553 | int w; | 
|---|
| 1554 |  | 
|---|
| 1555 | left = *row++; | 
|---|
| 1556 | w = ((left&1)-1) | (left&1); | 
|---|
| 1557 | rowlen--; | 
|---|
| 1558 | do { | 
|---|
| 1559 | right  = *row++; | 
|---|
| 1560 | rowlen--; | 
|---|
| 1561 | w += ((right&1)-1) | (right&1); | 
|---|
| 1562 | } while (w != 0); | 
|---|
| 1563 | left &= ~1; | 
|---|
| 1564 | right &= ~1; | 
|---|
| 1565 | } | 
|---|
| 1566 |  | 
|---|
| 1567 | if (right > left) { | 
|---|
| 1568 | *rowout++ = left; | 
|---|
| 1569 | *rowout++ = right; | 
|---|
| 1570 | } | 
|---|
| 1571 | } | 
|---|
| 1572 | *rowstart = (rowout-rowstart)-1; | 
|---|
| 1573 | } | 
|---|
| 1574 | } | 
|---|
| 1575 |  | 
|---|
| 1576 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1577 | if (debugging_scan_converter) | 
|---|
| 1578 | { | 
|---|
| 1579 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1580 | fz_write_printf(ctx, err, "Before render:\n"); | 
|---|
| 1581 | fz_edgebuffer_print(ctx, err, eb); | 
|---|
| 1582 | } | 
|---|
| 1583 | #endif | 
|---|
| 1584 |  | 
|---|
| 1585 | n = pix->n; | 
|---|
| 1586 | a = pix->alpha; | 
|---|
| 1587 | pl = fz_maxi(ras->clip.x0, pix->x); | 
|---|
| 1588 | pr = fz_mini(ras->clip.x1, pix->x + pix->w); | 
|---|
| 1589 | pr -= pl; | 
|---|
| 1590 | out = pix->samples + pix->stride * fz_maxi(ras->clip.y0 - pix->y, 0) + fz_maxi(ras->clip.x0 - pix->x, 0) * n; | 
|---|
| 1591 | if (scanlines > pix->y + pix->h - ras->clip.y0) | 
|---|
| 1592 | scanlines = pix->y + pix->h - ras->clip.y0; | 
|---|
| 1593 | for (i = fz_maxi(pix->y - ras->clip.y0, 0); i < scanlines; i++) { | 
|---|
| 1594 | int *row = &table[index[i]]; | 
|---|
| 1595 | int  rowlen = *row++; | 
|---|
| 1596 |  | 
|---|
| 1597 | while (rowlen > 0) { | 
|---|
| 1598 | int left, right; | 
|---|
| 1599 |  | 
|---|
| 1600 | left  = *row++; | 
|---|
| 1601 | right = *row++; | 
|---|
| 1602 | rowlen -= 2; | 
|---|
| 1603 | left  = fixed2int(left + fixed_half) - pl; | 
|---|
| 1604 | right = fixed2int(right + fixed_half) - pl; | 
|---|
| 1605 |  | 
|---|
| 1606 | if (right <= 0) | 
|---|
| 1607 | continue; | 
|---|
| 1608 | if (left >= pr) | 
|---|
| 1609 | continue; | 
|---|
| 1610 | if (right > pr) | 
|---|
| 1611 | right = pr; | 
|---|
| 1612 | if (left < 0) | 
|---|
| 1613 | left = 0; | 
|---|
| 1614 | right -= left; | 
|---|
| 1615 | if (right > 0) { | 
|---|
| 1616 | (*fn)(out + left*n, n, right, color, a, eop); | 
|---|
| 1617 | } | 
|---|
| 1618 | } | 
|---|
| 1619 | out += pix->stride; | 
|---|
| 1620 | } | 
|---|
| 1621 | } | 
|---|
| 1622 |  | 
|---|
| 1623 | static int edgecmp(const void *a, const void *b) | 
|---|
| 1624 | { | 
|---|
| 1625 | int left  = ((int*)a)[0]; | 
|---|
| 1626 | int right = ((int*)b)[0]; | 
|---|
| 1627 | left -= right; | 
|---|
| 1628 | if (left) | 
|---|
| 1629 | return left; | 
|---|
| 1630 | return ((int*)a)[1] - ((int*)b)[1]; | 
|---|
| 1631 | } | 
|---|
| 1632 |  | 
|---|
| 1633 | static void fz_convert_edgebuffer_app(fz_context *ctx, fz_rasterizer *ras, int eofill, const fz_irect *clip, fz_pixmap *pix, unsigned char *color, fz_overprint *eop) | 
|---|
| 1634 | { | 
|---|
| 1635 | fz_edgebuffer *eb = (fz_edgebuffer *)ras; | 
|---|
| 1636 | int scanlines = ras->clip.y1 - ras->clip.y0; | 
|---|
| 1637 | int i, n, a, pl, pr; | 
|---|
| 1638 | int *table = eb->table; | 
|---|
| 1639 | int *index = eb->index; | 
|---|
| 1640 | uint8_t *out; | 
|---|
| 1641 | fz_solid_color_painter_t *fn; | 
|---|
| 1642 |  | 
|---|
| 1643 | fn = fz_get_solid_color_painter(pix->n, color, pix->alpha, eop); | 
|---|
| 1644 | assert(fn); | 
|---|
| 1645 | if (fn == NULL) | 
|---|
| 1646 | return; | 
|---|
| 1647 |  | 
|---|
| 1648 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1649 | if (debugging_scan_converter) | 
|---|
| 1650 | { | 
|---|
| 1651 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1652 | fz_write_printf(ctx, err, "Before sort:\n"); | 
|---|
| 1653 | fz_edgebuffer_print_app(ctx, err, eb); | 
|---|
| 1654 | } | 
|---|
| 1655 | #endif | 
|---|
| 1656 |  | 
|---|
| 1657 | if (!eb->sorted) | 
|---|
| 1658 | { | 
|---|
| 1659 | eb->sorted = 1; | 
|---|
| 1660 | for (i = 0; i < scanlines; i++) | 
|---|
| 1661 | { | 
|---|
| 1662 | int *row = &table[index[i]]; | 
|---|
| 1663 | int rowlen = *row++; | 
|---|
| 1664 |  | 
|---|
| 1665 | /* Bubblesort short runs, qsort longer ones. */ | 
|---|
| 1666 | /* FIXME: Check "6" below */ | 
|---|
| 1667 | if (rowlen <= 6) { | 
|---|
| 1668 | int j, k; | 
|---|
| 1669 | for (j = 0; j < rowlen-1; j++) { | 
|---|
| 1670 | int * FZ_RESTRICT t = &row[j<<1]; | 
|---|
| 1671 | for (k = j+1; k < rowlen; k++) { | 
|---|
| 1672 | int * FZ_RESTRICT s = &row[k<<1]; | 
|---|
| 1673 | int tmp; | 
|---|
| 1674 | if (t[0] < s[0]) | 
|---|
| 1675 | continue; | 
|---|
| 1676 | if (t[0] > s[0]) | 
|---|
| 1677 | tmp = t[0], t[0] = s[0], s[0] = tmp; | 
|---|
| 1678 | else if (t[0] <= s[1]) | 
|---|
| 1679 | continue; | 
|---|
| 1680 | tmp = t[1]; t[1] = s[1]; s[1] = tmp; | 
|---|
| 1681 | } | 
|---|
| 1682 | } | 
|---|
| 1683 | } else | 
|---|
| 1684 | qsort(row, rowlen, 2*sizeof(int), edgecmp); | 
|---|
| 1685 | } | 
|---|
| 1686 |  | 
|---|
| 1687 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1688 | if (debugging_scan_converter) | 
|---|
| 1689 | { | 
|---|
| 1690 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1691 | fz_write_printf(ctx, err, "Before filter: %s\n", eofill ? "EO": "NZ"); | 
|---|
| 1692 | fz_edgebuffer_print_app(ctx, err, eb); | 
|---|
| 1693 | } | 
|---|
| 1694 | #endif | 
|---|
| 1695 |  | 
|---|
| 1696 | for (i=0; i < scanlines; i++) { | 
|---|
| 1697 | int *row = &table[index[i]]; | 
|---|
| 1698 | int rowlen = *row++; | 
|---|
| 1699 | int *rowstart = row; | 
|---|
| 1700 | int *rowout = row; | 
|---|
| 1701 | int  ll, lr, rl, rr, wind, marked_to; | 
|---|
| 1702 |  | 
|---|
| 1703 | /* Avoid double setting pixels, by keeping where we have marked to. */ | 
|---|
| 1704 | marked_to = int2fixed(clip->x0); | 
|---|
| 1705 | while (rowlen > 0) { | 
|---|
| 1706 | if (eofill) { | 
|---|
| 1707 | /* Even Odd */ | 
|---|
| 1708 | ll = (*row++)&~1; | 
|---|
| 1709 | lr = *row; | 
|---|
| 1710 | row += 2; | 
|---|
| 1711 | rowlen-=2; | 
|---|
| 1712 |  | 
|---|
| 1713 | /* We will fill solidly from ll to at least lr, possibly further */ | 
|---|
| 1714 | assert(rowlen >= 0); | 
|---|
| 1715 | rr = (*row++); | 
|---|
| 1716 | if (rr > lr) | 
|---|
| 1717 | lr = rr; | 
|---|
| 1718 | } else { | 
|---|
| 1719 | /* Non-Zero */ | 
|---|
| 1720 | int w; | 
|---|
| 1721 |  | 
|---|
| 1722 | ll = *row++; | 
|---|
| 1723 | lr = *row++; | 
|---|
| 1724 | wind = -(ll&1) | 1; | 
|---|
| 1725 | ll &= ~1; | 
|---|
| 1726 | rowlen--; | 
|---|
| 1727 |  | 
|---|
| 1728 | assert(rowlen > 0); | 
|---|
| 1729 | do { | 
|---|
| 1730 | rl = *row++; | 
|---|
| 1731 | rr = *row++; | 
|---|
| 1732 | w = -(rl&1) | 1; | 
|---|
| 1733 | rl &= ~1; | 
|---|
| 1734 | rowlen--; | 
|---|
| 1735 | if (rr > lr) | 
|---|
| 1736 | lr = rr; | 
|---|
| 1737 | wind += w; | 
|---|
| 1738 | if (wind == 0) | 
|---|
| 1739 | break; | 
|---|
| 1740 | } while (rowlen > 0); | 
|---|
| 1741 | } | 
|---|
| 1742 |  | 
|---|
| 1743 | if (marked_to >= lr) | 
|---|
| 1744 | continue; | 
|---|
| 1745 |  | 
|---|
| 1746 | if (marked_to >= ll) { | 
|---|
| 1747 | if (rowout == rowstart) | 
|---|
| 1748 | ll = marked_to; | 
|---|
| 1749 | else { | 
|---|
| 1750 | rowout -= 2; | 
|---|
| 1751 | ll = *rowout; | 
|---|
| 1752 | } | 
|---|
| 1753 | } | 
|---|
| 1754 |  | 
|---|
| 1755 | if (lr > ll) { | 
|---|
| 1756 | *rowout++ = ll; | 
|---|
| 1757 | *rowout++ = lr; | 
|---|
| 1758 | marked_to = lr; | 
|---|
| 1759 | } | 
|---|
| 1760 | } | 
|---|
| 1761 | rowstart[-1] = rowout-rowstart; | 
|---|
| 1762 | } | 
|---|
| 1763 | } | 
|---|
| 1764 |  | 
|---|
| 1765 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1766 | if (debugging_scan_converter) | 
|---|
| 1767 | { | 
|---|
| 1768 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1769 | fz_write_printf(ctx, err, "Before render:\n"); | 
|---|
| 1770 | fz_edgebuffer_print_app(ctx, err, eb); | 
|---|
| 1771 | } | 
|---|
| 1772 | #endif | 
|---|
| 1773 |  | 
|---|
| 1774 | n = pix->n; | 
|---|
| 1775 | a = pix->alpha; | 
|---|
| 1776 | pl = clip->x0; | 
|---|
| 1777 | pr = clip->x1 - pl; | 
|---|
| 1778 | out = pix->samples + pix->stride * (clip->y0 - pix->y) + (clip->x0 - pix->x) * n; | 
|---|
| 1779 | if (scanlines > clip->y1 - ras->clip.y0) | 
|---|
| 1780 | scanlines = clip->y1 - ras->clip.y0; | 
|---|
| 1781 |  | 
|---|
| 1782 | i = (clip->y0 - ras->clip.y0); | 
|---|
| 1783 | if (i < 0) | 
|---|
| 1784 | return; | 
|---|
| 1785 | for (; i < scanlines; i++) { | 
|---|
| 1786 | int *row = &table[index[i]]; | 
|---|
| 1787 | int  rowlen = *row++; | 
|---|
| 1788 |  | 
|---|
| 1789 | while (rowlen > 0) { | 
|---|
| 1790 | int left, right; | 
|---|
| 1791 |  | 
|---|
| 1792 | left  = *row++; | 
|---|
| 1793 | right = *row++; | 
|---|
| 1794 | rowlen -= 2; | 
|---|
| 1795 | left  = fixed2int(left + fixed_half) - pl; | 
|---|
| 1796 | right = fixed2int(right + fixed_half) - pl; | 
|---|
| 1797 |  | 
|---|
| 1798 | if (right <= 0) | 
|---|
| 1799 | continue; | 
|---|
| 1800 | if (left >= pr) | 
|---|
| 1801 | break; | 
|---|
| 1802 | if (right > pr) | 
|---|
| 1803 | right = pr; | 
|---|
| 1804 | if (left < 0) | 
|---|
| 1805 | left = 0; | 
|---|
| 1806 | right -= left; | 
|---|
| 1807 | if (right > 0) { | 
|---|
| 1808 | (*fn)(out + left*n, n, right, color, a, eop); | 
|---|
| 1809 | } | 
|---|
| 1810 | } | 
|---|
| 1811 | out += pix->stride; | 
|---|
| 1812 | } | 
|---|
| 1813 | } | 
|---|
| 1814 |  | 
|---|
| 1815 | static void fz_gap_edgebuffer(fz_context *ctx, fz_rasterizer *ras) | 
|---|
| 1816 | { | 
|---|
| 1817 | fz_edgebuffer *eb = (fz_edgebuffer *)ras; | 
|---|
| 1818 |  | 
|---|
| 1819 | if (eb->app) | 
|---|
| 1820 | { | 
|---|
| 1821 | #ifdef DEBUG_SCAN_CONVERTER | 
|---|
| 1822 | if (0 && debugging_scan_converter) | 
|---|
| 1823 | { | 
|---|
| 1824 | fz_output *err = fz_stderr(ctx); | 
|---|
| 1825 | fz_write_printf(ctx, fz_stderr(ctx), "Pen up move.\n"); | 
|---|
| 1826 | fz_write_printf(ctx, err, "Before flush:\n"); | 
|---|
| 1827 | fz_edgebuffer_print_app(ctx, err, eb); | 
|---|
| 1828 | } | 
|---|
| 1829 | #endif | 
|---|
| 1830 | cursor_flush(eb); | 
|---|
| 1831 | eb->cursor[0].saved = 0; | 
|---|
| 1832 | eb->cursor[0].unset = 1; | 
|---|
| 1833 | eb->cursor[0].can_save = 1; | 
|---|
| 1834 | eb->cursor[0].d = DIRN_UNSET; | 
|---|
| 1835 | eb->cursor[1].saved = 0; | 
|---|
| 1836 | eb->cursor[1].unset = 1; | 
|---|
| 1837 | eb->cursor[1].can_save = 1; | 
|---|
| 1838 | eb->cursor[1].d = DIRN_UNSET; | 
|---|
| 1839 | eb->cursor[2].saved = 0; | 
|---|
| 1840 | eb->cursor[2].unset = 1; | 
|---|
| 1841 | eb->cursor[2].can_save = 1; | 
|---|
| 1842 | eb->cursor[2].d = DIRN_UNSET; | 
|---|
| 1843 | } | 
|---|
| 1844 | } | 
|---|
| 1845 |  | 
|---|
| 1846 | static int fz_is_rect_edgebuffer(fz_context *ctx, fz_rasterizer *r) | 
|---|
| 1847 | { | 
|---|
| 1848 | return 0; | 
|---|
| 1849 | } | 
|---|
| 1850 |  | 
|---|
| 1851 | static const fz_rasterizer_fns edgebuffer_app = | 
|---|
| 1852 | { | 
|---|
| 1853 | fz_drop_edgebuffer, | 
|---|
| 1854 | fz_reset_edgebuffer, | 
|---|
| 1855 | fz_postindex_edgebuffer, | 
|---|
| 1856 | fz_insert_edgebuffer_app, | 
|---|
| 1857 | NULL, | 
|---|
| 1858 | fz_gap_edgebuffer, | 
|---|
| 1859 | fz_convert_edgebuffer_app, | 
|---|
| 1860 | fz_is_rect_edgebuffer, | 
|---|
| 1861 | 1 /* Reusable */ | 
|---|
| 1862 | }; | 
|---|
| 1863 |  | 
|---|
| 1864 | static const fz_rasterizer_fns edgebuffer_cop = | 
|---|
| 1865 | { | 
|---|
| 1866 | fz_drop_edgebuffer, | 
|---|
| 1867 | fz_reset_edgebuffer, | 
|---|
| 1868 | fz_postindex_edgebuffer, | 
|---|
| 1869 | fz_insert_edgebuffer, | 
|---|
| 1870 | NULL, | 
|---|
| 1871 | NULL, /* gap */ | 
|---|
| 1872 | fz_convert_edgebuffer, | 
|---|
| 1873 | fz_is_rect_edgebuffer, | 
|---|
| 1874 | 1 /* Reusable */ | 
|---|
| 1875 | }; | 
|---|
| 1876 |  | 
|---|
| 1877 | fz_rasterizer * | 
|---|
| 1878 | fz_new_edgebuffer(fz_context *ctx, fz_edgebuffer_rule rule) | 
|---|
| 1879 | { | 
|---|
| 1880 | fz_edgebuffer *eb; | 
|---|
| 1881 | eb = fz_new_derived_rasterizer(ctx, fz_edgebuffer, rule == FZ_EDGEBUFFER_ANY_PART_OF_PIXEL ? &edgebuffer_app : &edgebuffer_cop); | 
|---|
| 1882 | eb->app = rule == FZ_EDGEBUFFER_ANY_PART_OF_PIXEL; | 
|---|
| 1883 | return &eb->super; | 
|---|
| 1884 | } | 
|---|
| 1885 |  | 
|---|