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