1 //========================================================================
2 //
3 // Splash.cc
4 //
5 //========================================================================
6
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
10 //
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
13 //
14 // Copyright (C) 2005-2010 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
16 // Copyright (C) 2010 Thomas Freitag <Thomas.Freitag@alfa.de>
17 // Copyright (C) 2010 Christian Feuers�nger <cfeuersaenger@googlemail.com>
18 //
19 // To see a description of the changes please see the Changelog file that
20 // came with your tarball or type make ChangeLog if you are building from git
21 //
22 //========================================================================
23
24 #include <config.h>
25
26 #ifdef USE_GCC_PRAGMAS
27 #pragma implementation
28 #endif
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <assert.h>
34 #include "goo/gmem.h"
35 #include "goo/GooLikely.h"
36 #include "poppler/Error.h"
37 #include "SplashErrorCodes.h"
38 #include "SplashMath.h"
39 #include "SplashBitmap.h"
40 #include "SplashState.h"
41 #include "SplashPath.h"
42 #include "SplashXPath.h"
43 #include "SplashXPathScanner.h"
44 #include "SplashPattern.h"
45 #include "SplashScreen.h"
46 #include "SplashFont.h"
47 #include "SplashGlyphBitmap.h"
48 #include "Splash.h"
49
50 //------------------------------------------------------------------------
51
52 // distance of Bezier control point from center for circle approximation
53 // = (4 * (sqrt(2) - 1) / 3) * r
54 #define bezierCircle ((SplashCoord)0.55228475)
55 #define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
56
57 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
div255(int x)58 static inline Guchar div255(int x) {
59 return (Guchar)((x + (x >> 8) + 0x80) >> 8);
60 }
61
62 template<typename T>
Guswap(T & a,T & b)63 inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
64
65 //------------------------------------------------------------------------
66 // SplashPipe
67 //------------------------------------------------------------------------
68
69 #define splashPipeMaxStages 9
70
71 struct SplashPipe {
72 // pixel coordinates
73 int x, y;
74
75 // source pattern
76 SplashPattern *pattern;
77
78 // source alpha and color
79 SplashCoord aInput;
80 GBool usesShape;
81 Guchar aSrc;
82 SplashColorPtr cSrc;
83 SplashColor cSrcVal;
84
85 // non-isolated group alpha0
86 Guchar *alpha0Ptr;
87
88 // soft mask
89 SplashColorPtr softMaskPtr;
90
91 // destination alpha and color
92 SplashColorPtr destColorPtr;
93 int destColorMask;
94 Guchar *destAlphaPtr;
95
96 // shape
97 SplashCoord shape;
98
99 // result alpha and color
100 GBool noTransparency;
101 SplashPipeResultColorCtrl resultColorCtrl;
102
103 // non-isolated group correction
104 int nonIsolatedGroup;
105 };
106
107 SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
108 splashPipeResultColorNoAlphaBlendMono,
109 splashPipeResultColorNoAlphaBlendMono,
110 splashPipeResultColorNoAlphaBlendRGB,
111 splashPipeResultColorNoAlphaBlendRGB,
112 splashPipeResultColorNoAlphaBlendRGB
113 #if SPLASH_CMYK
114 ,
115 splashPipeResultColorNoAlphaBlendCMYK
116 #endif
117 };
118
119 SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
120 splashPipeResultColorAlphaNoBlendMono,
121 splashPipeResultColorAlphaNoBlendMono,
122 splashPipeResultColorAlphaNoBlendRGB,
123 splashPipeResultColorNoAlphaBlendRGB,
124 splashPipeResultColorAlphaNoBlendRGB
125 #if SPLASH_CMYK
126 ,
127 splashPipeResultColorAlphaNoBlendCMYK
128 #endif
129 };
130
131 SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
132 splashPipeResultColorAlphaBlendMono,
133 splashPipeResultColorAlphaBlendMono,
134 splashPipeResultColorAlphaBlendRGB,
135 splashPipeResultColorNoAlphaBlendRGB,
136 splashPipeResultColorAlphaBlendRGB
137 #if SPLASH_CMYK
138 ,
139 splashPipeResultColorAlphaBlendCMYK
140 #endif
141 };
142
143 //------------------------------------------------------------------------
144
blendXor(SplashColorPtr src,SplashColorPtr dest,SplashColorPtr blend,SplashColorMode cm)145 static void blendXor(SplashColorPtr src, SplashColorPtr dest,
146 SplashColorPtr blend, SplashColorMode cm) {
147 int i;
148
149 for (i = 0; i < splashColorModeNComps[cm]; ++i) {
150 blend[i] = src[i] ^ dest[i];
151 }
152 }
153
154 //------------------------------------------------------------------------
155 // modified region
156 //------------------------------------------------------------------------
157
clearModRegion()158 void Splash::clearModRegion() {
159 modXMin = bitmap->getWidth();
160 modYMin = bitmap->getHeight();
161 modXMax = -1;
162 modYMax = -1;
163 }
164
updateModX(int x)165 inline void Splash::updateModX(int x) {
166 if (x < modXMin) {
167 modXMin = x;
168 }
169 if (x > modXMax) {
170 modXMax = x;
171 }
172 }
173
updateModY(int y)174 inline void Splash::updateModY(int y) {
175 if (y < modYMin) {
176 modYMin = y;
177 }
178 if (y > modYMax) {
179 modYMax = y;
180 }
181 }
182
183 //------------------------------------------------------------------------
184 // pipeline
185 //------------------------------------------------------------------------
186
pipeInit(SplashPipe * pipe,int x,int y,SplashPattern * pattern,SplashColorPtr cSrc,SplashCoord aInput,GBool usesShape,GBool nonIsolatedGroup)187 inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
188 SplashPattern *pattern, SplashColorPtr cSrc,
189 SplashCoord aInput, GBool usesShape,
190 GBool nonIsolatedGroup) {
191 pipeSetXY(pipe, x, y);
192 pipe->pattern = NULL;
193
194 // source color
195 if (pattern) {
196 if (pattern->isStatic()) {
197 pattern->getColor(x, y, pipe->cSrcVal);
198 } else {
199 pipe->pattern = pattern;
200 }
201 pipe->cSrc = pipe->cSrcVal;
202 } else {
203 pipe->cSrc = cSrc;
204 }
205
206 // source alpha
207 pipe->aInput = aInput;
208 if (!state->softMask) {
209 if (usesShape) {
210 pipe->aInput *= 255;
211 } else {
212 pipe->aSrc = (Guchar)splashRound(pipe->aInput * 255);
213 }
214 }
215 pipe->usesShape = usesShape;
216
217 // result alpha
218 if (aInput == 1 && !state->softMask && !usesShape &&
219 !state->inNonIsolatedGroup) {
220 pipe->noTransparency = gTrue;
221 } else {
222 pipe->noTransparency = gFalse;
223 }
224
225 // result color
226 if (pipe->noTransparency) {
227 // the !state->blendFunc case is handled separately in pipeRun
228 pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode];
229 } else if (!state->blendFunc) {
230 pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode];
231 } else {
232 pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode];
233 }
234
235 // non-isolated group correction
236 if (nonIsolatedGroup) {
237 pipe->nonIsolatedGroup = splashColorModeNComps[bitmap->mode];
238 } else {
239 pipe->nonIsolatedGroup = 0;
240 }
241 }
242
pipeRun(SplashPipe * pipe)243 inline void Splash::pipeRun(SplashPipe *pipe) {
244 Guchar aSrc, aDest, alpha2, alpha0, aResult;
245 SplashColor cDest, cBlend;
246 Guchar cResult0, cResult1, cResult2, cResult3;
247
248 //----- source color
249
250 // static pattern: handled in pipeInit
251 // fixed color: handled in pipeInit
252
253 // dynamic pattern
254 if (pipe->pattern) {
255 if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) {
256 switch (bitmap->mode) {
257 case splashModeMono1:
258 if (!(pipe->destColorMask >>= 1))
259 ++pipe->destColorPtr;
260 break;
261 case splashModeMono8:
262 ++pipe->destColorPtr;
263 break;
264 case splashModeBGR8:
265 case splashModeRGB8:
266 pipe->destColorPtr += 3;
267 break;
268 case splashModeXBGR8:
269 #if SPLASH_CMYK
270 case splashModeCMYK8:
271 #endif
272 pipe->destColorPtr += 4;
273 break;
274 }
275 if (pipe->destAlphaPtr) {
276 ++pipe->destAlphaPtr;
277 }
278 ++pipe->x;
279 return;
280 }
281 }
282
283 if (pipe->noTransparency && !state->blendFunc) {
284
285 //----- write destination pixel
286
287 switch (bitmap->mode) {
288 case splashModeMono1:
289 cResult0 = pipe->cSrc[0];
290 if (state->screen->test(pipe->x, pipe->y, cResult0)) {
291 *pipe->destColorPtr |= pipe->destColorMask;
292 } else {
293 *pipe->destColorPtr &= ~pipe->destColorMask;
294 }
295 if (!(pipe->destColorMask >>= 1)) {
296 pipe->destColorMask = 0x80;
297 ++pipe->destColorPtr;
298 }
299 break;
300 case splashModeMono8:
301 *pipe->destColorPtr++ = pipe->cSrc[0];
302 break;
303 case splashModeRGB8:
304 *pipe->destColorPtr++ = pipe->cSrc[0];
305 *pipe->destColorPtr++ = pipe->cSrc[1];
306 *pipe->destColorPtr++ = pipe->cSrc[2];
307 break;
308 case splashModeXBGR8:
309 *pipe->destColorPtr++ = pipe->cSrc[2];
310 *pipe->destColorPtr++ = pipe->cSrc[1];
311 *pipe->destColorPtr++ = pipe->cSrc[0];
312 *pipe->destColorPtr++ = 255;
313 break;
314 case splashModeBGR8:
315 *pipe->destColorPtr++ = pipe->cSrc[2];
316 *pipe->destColorPtr++ = pipe->cSrc[1];
317 *pipe->destColorPtr++ = pipe->cSrc[0];
318 break;
319 #if SPLASH_CMYK
320 case splashModeCMYK8:
321 *pipe->destColorPtr++ = pipe->cSrc[0];
322 *pipe->destColorPtr++ = pipe->cSrc[1];
323 *pipe->destColorPtr++ = pipe->cSrc[2];
324 *pipe->destColorPtr++ = pipe->cSrc[3];
325 break;
326 #endif
327 }
328 if (pipe->destAlphaPtr) {
329 *pipe->destAlphaPtr++ = 255;
330 }
331
332 } else {
333
334 //----- read destination pixel
335
336 switch (bitmap->mode) {
337 case splashModeMono1:
338 cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
339 break;
340 case splashModeMono8:
341 cDest[0] = *pipe->destColorPtr;
342 break;
343 case splashModeRGB8:
344 cDest[0] = pipe->destColorPtr[0];
345 cDest[1] = pipe->destColorPtr[1];
346 cDest[2] = pipe->destColorPtr[2];
347 break;
348 case splashModeXBGR8:
349 cDest[0] = pipe->destColorPtr[2];
350 cDest[1] = pipe->destColorPtr[1];
351 cDest[2] = pipe->destColorPtr[0];
352 cDest[3] = 255;
353 break;
354 case splashModeBGR8:
355 cDest[0] = pipe->destColorPtr[2];
356 cDest[1] = pipe->destColorPtr[1];
357 cDest[2] = pipe->destColorPtr[0];
358 break;
359 #if SPLASH_CMYK
360 case splashModeCMYK8:
361 cDest[0] = pipe->destColorPtr[0];
362 cDest[1] = pipe->destColorPtr[1];
363 cDest[2] = pipe->destColorPtr[2];
364 cDest[3] = pipe->destColorPtr[3];
365 break;
366 #endif
367 }
368 if (pipe->destAlphaPtr) {
369 aDest = *pipe->destAlphaPtr;
370 } else {
371 aDest = 0xff;
372 }
373
374 //----- blend function
375
376 if (state->blendFunc) {
377 (*state->blendFunc)(pipe->cSrc, cDest, cBlend, bitmap->mode);
378 }
379
380 //----- source alpha
381
382 if (state->softMask) {
383 if (pipe->usesShape) {
384 aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++
385 * pipe->shape);
386 } else {
387 aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++);
388 }
389 } else if (pipe->usesShape) {
390 // pipe->aInput is premultiplied by 255 in pipeInit
391 aSrc = (Guchar)splashRound(pipe->aInput * pipe->shape);
392 } else {
393 // precomputed in pipeInit
394 aSrc = pipe->aSrc;
395 }
396
397 //----- result alpha and non-isolated group element correction
398
399 if (pipe->noTransparency) {
400 alpha2 = aResult = 255;
401 } else {
402 aResult = aSrc + aDest - div255(aSrc * aDest);
403
404 if (pipe->alpha0Ptr) {
405 alpha0 = *pipe->alpha0Ptr++;
406 alpha2 = aResult + alpha0 - div255(aResult * alpha0);
407 } else {
408 alpha2 = aResult;
409 }
410 }
411
412 //----- result color
413
414 cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
415
416 switch (pipe->resultColorCtrl) {
417
418 #if SPLASH_CMYK
419 case splashPipeResultColorNoAlphaBlendCMYK:
420 cResult3 = div255((255 - aDest) * pipe->cSrc[3] + aDest * cBlend[3]);
421 #endif
422 case splashPipeResultColorNoAlphaBlendRGB:
423 cResult2 = div255((255 - aDest) * pipe->cSrc[2] + aDest * cBlend[2]);
424 cResult1 = div255((255 - aDest) * pipe->cSrc[1] + aDest * cBlend[1]);
425 case splashPipeResultColorNoAlphaBlendMono:
426 cResult0 = div255((255 - aDest) * pipe->cSrc[0] + aDest * cBlend[0]);
427 break;
428
429 case splashPipeResultColorAlphaNoBlendMono:
430 if (alpha2 == 0) {
431 cResult0 = 0;
432 } else {
433 cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
434 aSrc * pipe->cSrc[0]) / alpha2);
435 }
436 break;
437 case splashPipeResultColorAlphaNoBlendRGB:
438 if (alpha2 == 0) {
439 cResult0 = 0;
440 cResult1 = 0;
441 cResult2 = 0;
442 } else {
443 cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
444 aSrc * pipe->cSrc[0]) / alpha2);
445 cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
446 aSrc * pipe->cSrc[1]) / alpha2);
447 cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
448 aSrc * pipe->cSrc[2]) / alpha2);
449 }
450 break;
451 #if SPLASH_CMYK
452 case splashPipeResultColorAlphaNoBlendCMYK:
453 if (alpha2 == 0) {
454 cResult0 = 0;
455 cResult1 = 0;
456 cResult2 = 0;
457 cResult3 = 0;
458 } else {
459 cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
460 aSrc * pipe->cSrc[0]) / alpha2);
461 cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
462 aSrc * pipe->cSrc[1]) / alpha2);
463 cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
464 aSrc * pipe->cSrc[2]) / alpha2);
465 cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
466 aSrc * pipe->cSrc[3]) / alpha2);
467 }
468 break;
469 #endif
470
471 case splashPipeResultColorAlphaBlendMono:
472 if (alpha2 == 0) {
473 cResult0 = 0;
474 } else {
475 cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
476 aSrc * ((255 - aDest) * pipe->cSrc[0] +
477 aDest * cBlend[0]) / 255) /
478 alpha2);
479 }
480 break;
481 case splashPipeResultColorAlphaBlendRGB:
482 if (alpha2 == 0) {
483 cResult0 = 0;
484 cResult1 = 0;
485 cResult2 = 0;
486 } else {
487 cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
488 aSrc * ((255 - aDest) * pipe->cSrc[0] +
489 aDest * cBlend[0]) / 255) /
490 alpha2);
491 cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
492 aSrc * ((255 - aDest) * pipe->cSrc[1] +
493 aDest * cBlend[1]) / 255) /
494 alpha2);
495 cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
496 aSrc * ((255 - aDest) * pipe->cSrc[2] +
497 aDest * cBlend[2]) / 255) /
498 alpha2);
499 }
500 break;
501 #if SPLASH_CMYK
502 case splashPipeResultColorAlphaBlendCMYK:
503 if (alpha2 == 0) {
504 cResult0 = 0;
505 cResult1 = 0;
506 cResult2 = 0;
507 cResult3 = 0;
508 } else {
509 cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
510 aSrc * ((255 - aDest) * pipe->cSrc[0] +
511 aDest * cBlend[0]) / 255) /
512 alpha2);
513 cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
514 aSrc * ((255 - aDest) * pipe->cSrc[1] +
515 aDest * cBlend[1]) / 255) /
516 alpha2);
517 cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
518 aSrc * ((255 - aDest) * pipe->cSrc[2] +
519 aDest * cBlend[2]) / 255) /
520 alpha2);
521 cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
522 aSrc * ((255 - aDest) * pipe->cSrc[3] +
523 aDest * cBlend[3]) / 255) /
524 alpha2);
525 }
526 break;
527 #endif
528 }
529
530 //----- non-isolated group correction
531
532 if (aResult != 0) {
533 switch (pipe->nonIsolatedGroup) {
534 #if SPLASH_CMYK
535 case 4:
536 cResult3 += (cResult3 - cDest[3]) * aDest *
537 (255 - aResult) / (255 * aResult);
538 #endif
539 case 3:
540 cResult2 += (cResult2 - cDest[2]) * aDest *
541 (255 - aResult) / (255 * aResult);
542 cResult1 += (cResult1 - cDest[1]) * aDest *
543 (255 - aResult) / (255 * aResult);
544 case 1:
545 cResult0 += (cResult0 - cDest[0]) * aDest *
546 (255 - aResult) / (255 * aResult);
547 case 0:
548 break;
549 }
550 }
551
552 //----- write destination pixel
553
554 switch (bitmap->mode) {
555 case splashModeMono1:
556 if (state->screen->test(pipe->x, pipe->y, cResult0)) {
557 *pipe->destColorPtr |= pipe->destColorMask;
558 } else {
559 *pipe->destColorPtr &= ~pipe->destColorMask;
560 }
561 if (!(pipe->destColorMask >>= 1)) {
562 pipe->destColorMask = 0x80;
563 ++pipe->destColorPtr;
564 }
565 break;
566 case splashModeMono8:
567 *pipe->destColorPtr++ = cResult0;
568 break;
569 case splashModeRGB8:
570 *pipe->destColorPtr++ = cResult0;
571 *pipe->destColorPtr++ = cResult1;
572 *pipe->destColorPtr++ = cResult2;
573 break;
574 case splashModeXBGR8:
575 *pipe->destColorPtr++ = cResult2;
576 *pipe->destColorPtr++ = cResult1;
577 *pipe->destColorPtr++ = cResult0;
578 *pipe->destColorPtr++ = 255;
579 break;
580 case splashModeBGR8:
581 *pipe->destColorPtr++ = cResult2;
582 *pipe->destColorPtr++ = cResult1;
583 *pipe->destColorPtr++ = cResult0;
584 break;
585 #if SPLASH_CMYK
586 case splashModeCMYK8:
587 *pipe->destColorPtr++ = cResult0;
588 *pipe->destColorPtr++ = cResult1;
589 *pipe->destColorPtr++ = cResult2;
590 *pipe->destColorPtr++ = cResult3;
591 break;
592 #endif
593 }
594 if (pipe->destAlphaPtr) {
595 *pipe->destAlphaPtr++ = aResult;
596 }
597
598 }
599
600 ++pipe->x;
601 }
602
pipeSetXY(SplashPipe * pipe,int x,int y)603 inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
604 pipe->x = x;
605 pipe->y = y;
606 if (state->softMask) {
607 pipe->softMaskPtr =
608 &state->softMask->data[y * state->softMask->rowSize + x];
609 }
610 switch (bitmap->mode) {
611 case splashModeMono1:
612 pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
613 pipe->destColorMask = 0x80 >> (x & 7);
614 break;
615 case splashModeMono8:
616 pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x];
617 break;
618 case splashModeRGB8:
619 case splashModeBGR8:
620 pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x];
621 break;
622 case splashModeXBGR8:
623 pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
624 break;
625 #if SPLASH_CMYK
626 case splashModeCMYK8:
627 pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
628 break;
629 #endif
630 }
631 if (bitmap->alpha) {
632 pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
633 } else {
634 pipe->destAlphaPtr = NULL;
635 }
636 if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
637 pipe->alpha0Ptr =
638 &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
639 (alpha0X + x)];
640 } else {
641 pipe->alpha0Ptr = NULL;
642 }
643 }
644
pipeIncX(SplashPipe * pipe)645 inline void Splash::pipeIncX(SplashPipe *pipe) {
646 ++pipe->x;
647 if (state->softMask) {
648 ++pipe->softMaskPtr;
649 }
650 switch (bitmap->mode) {
651 case splashModeMono1:
652 if (!(pipe->destColorMask >>= 1)) {
653 pipe->destColorMask = 0x80;
654 ++pipe->destColorPtr;
655 }
656 break;
657 case splashModeMono8:
658 ++pipe->destColorPtr;
659 break;
660 case splashModeRGB8:
661 case splashModeBGR8:
662 pipe->destColorPtr += 3;
663 break;
664 case splashModeXBGR8:
665 pipe->destColorPtr += 4;
666 break;
667 #if SPLASH_CMYK
668 case splashModeCMYK8:
669 pipe->destColorPtr += 4;
670 break;
671 #endif
672 }
673 if (pipe->destAlphaPtr) {
674 ++pipe->destAlphaPtr;
675 }
676 if (pipe->alpha0Ptr) {
677 ++pipe->alpha0Ptr;
678 }
679 }
680
drawPixel(SplashPipe * pipe,int x,int y,GBool noClip)681 inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) {
682 if (unlikely(y < 0))
683 return;
684
685 if (noClip || state->clip->test(x, y)) {
686 pipeSetXY(pipe, x, y);
687 pipeRun(pipe);
688 updateModX(x);
689 updateModY(y);
690 }
691 }
692
drawAAPixelInit()693 inline void Splash::drawAAPixelInit() {
694 aaBufY = -1;
695 }
696
drawAAPixel(SplashPipe * pipe,int x,int y)697 inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
698 #if splashAASize == 4
699 static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
700 1, 2, 2, 3, 2, 3, 3, 4 };
701 int w;
702 #else
703 int xx, yy;
704 #endif
705 SplashColorPtr p;
706 int x0, x1, t;
707
708 if (x < 0 || x >= bitmap->width ||
709 y < state->clip->getYMinI() || y > state->clip->getYMaxI()) {
710 return;
711 }
712
713 // update aaBuf
714 if (y != aaBufY) {
715 memset(aaBuf->getDataPtr(), 0xff,
716 aaBuf->getRowSize() * aaBuf->getHeight());
717 x0 = 0;
718 x1 = bitmap->width - 1;
719 state->clip->clipAALine(aaBuf, &x0, &x1, y);
720 aaBufY = y;
721 }
722
723 // compute the shape value
724 #if splashAASize == 4
725 p = aaBuf->getDataPtr() + (x >> 1);
726 w = aaBuf->getRowSize();
727 if (x & 1) {
728 t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] +
729 bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f];
730 } else {
731 t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] +
732 bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4];
733 }
734 #else
735 t = 0;
736 for (yy = 0; yy < splashAASize; ++yy) {
737 for (xx = 0; xx < splashAASize; ++xx) {
738 p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
739 ((x * splashAASize + xx) >> 3);
740 t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
741 }
742 }
743 #endif
744
745 // draw the pixel
746 if (t != 0) {
747 pipeSetXY(pipe, x, y);
748 pipe->shape *= aaGamma[t];
749 pipeRun(pipe);
750 updateModX(x);
751 updateModY(y);
752 }
753 }
754
drawSpan(SplashPipe * pipe,int x0,int x1,int y,GBool noClip)755 inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
756 GBool noClip) {
757 int x;
758
759 pipeSetXY(pipe, x0, y);
760 if (noClip) {
761 for (x = x0; x <= x1; ++x) {
762 pipeRun(pipe);
763 }
764 updateModX(x0);
765 updateModX(x1);
766 updateModY(y);
767 } else {
768 for (x = x0; x <= x1; ++x) {
769 if (state->clip->test(x, y)) {
770 pipeRun(pipe);
771 updateModX(x);
772 updateModY(y);
773 } else {
774 pipeIncX(pipe);
775 }
776 }
777 }
778 }
779
drawAALine(SplashPipe * pipe,int x0,int x1,int y)780 inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) {
781 #if splashAASize == 4
782 static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
783 1, 2, 2, 3, 2, 3, 3, 4 };
784 SplashColorPtr p0, p1, p2, p3;
785 int t;
786 #else
787 SplashColorPtr p;
788 int xx, yy, t;
789 #endif
790 int x;
791
792 #if splashAASize == 4
793 p0 = aaBuf->getDataPtr() + (x0 >> 1);
794 p1 = p0 + aaBuf->getRowSize();
795 p2 = p1 + aaBuf->getRowSize();
796 p3 = p2 + aaBuf->getRowSize();
797 #endif
798 pipeSetXY(pipe, x0, y);
799 for (x = x0; x <= x1; ++x) {
800
801 // compute the shape value
802 #if splashAASize == 4
803 if (x & 1) {
804 t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] +
805 bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f];
806 ++p0; ++p1; ++p2; ++p3;
807 } else {
808 t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
809 bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
810 }
811 #else
812 t = 0;
813 for (yy = 0; yy < splashAASize; ++yy) {
814 for (xx = 0; xx < splashAASize; ++xx) {
815 p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
816 ((x * splashAASize + xx) >> 3);
817 t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
818 }
819 }
820 #endif
821
822 if (t != 0) {
823 pipe->shape = aaGamma[t];
824 pipeRun(pipe);
825 updateModX(x);
826 updateModY(y);
827 } else {
828 pipeIncX(pipe);
829 }
830 }
831 }
832
833 //------------------------------------------------------------------------
834
835 // Transform a point from user space to device space.
transform(SplashCoord * matrix,SplashCoord xi,SplashCoord yi,SplashCoord * xo,SplashCoord * yo)836 inline void Splash::transform(SplashCoord *matrix,
837 SplashCoord xi, SplashCoord yi,
838 SplashCoord *xo, SplashCoord *yo) {
839 // [ m[0] m[1] 0 ]
840 // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
841 // [ m[4] m[5] 1 ]
842 *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
843 *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
844 }
845
846 //------------------------------------------------------------------------
847 // Splash
848 //------------------------------------------------------------------------
849
Splash(SplashBitmap * bitmapA,GBool vectorAntialiasA,SplashScreenParams * screenParams)850 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
851 SplashScreenParams *screenParams) {
852 int i;
853
854 bitmap = bitmapA;
855 vectorAntialias = vectorAntialiasA;
856 state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
857 screenParams);
858 if (vectorAntialias) {
859 aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
860 1, splashModeMono1, gFalse);
861 for (i = 0; i <= splashAASize * splashAASize; ++i) {
862 aaGamma[i] = splashPow((SplashCoord)i /
863 (SplashCoord)(splashAASize * splashAASize),
864 1.5);
865 }
866 } else {
867 aaBuf = NULL;
868 }
869 clearModRegion();
870 debugMode = gFalse;
871 }
872
Splash(SplashBitmap * bitmapA,GBool vectorAntialiasA,SplashScreen * screenA)873 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
874 SplashScreen *screenA) {
875 int i;
876
877 bitmap = bitmapA;
878 vectorAntialias = vectorAntialiasA;
879 state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
880 screenA);
881 if (vectorAntialias) {
882 aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
883 1, splashModeMono1, gFalse);
884 for (i = 0; i <= splashAASize * splashAASize; ++i) {
885 aaGamma[i] = splashPow((SplashCoord)i /
886 (SplashCoord)(splashAASize * splashAASize),
887 1.5);
888 }
889 } else {
890 aaBuf = NULL;
891 }
892 clearModRegion();
893 debugMode = gFalse;
894 }
895
~Splash()896 Splash::~Splash() {
897 while (state->next) {
898 restoreState();
899 }
900 delete state;
901 if (vectorAntialias) {
902 delete aaBuf;
903 }
904 }
905
906 //------------------------------------------------------------------------
907 // state read
908 //------------------------------------------------------------------------
909
getMatrix()910 SplashCoord *Splash::getMatrix() {
911 return state->matrix;
912 }
913
getStrokePattern()914 SplashPattern *Splash::getStrokePattern() {
915 return state->strokePattern;
916 }
917
getFillPattern()918 SplashPattern *Splash::getFillPattern() {
919 return state->fillPattern;
920 }
921
getScreen()922 SplashScreen *Splash::getScreen() {
923 return state->screen;
924 }
925
getBlendFunc()926 SplashBlendFunc Splash::getBlendFunc() {
927 return state->blendFunc;
928 }
929
getStrokeAlpha()930 SplashCoord Splash::getStrokeAlpha() {
931 return state->strokeAlpha;
932 }
933
getFillAlpha()934 SplashCoord Splash::getFillAlpha() {
935 return state->fillAlpha;
936 }
937
getLineWidth()938 SplashCoord Splash::getLineWidth() {
939 return state->lineWidth;
940 }
941
getLineCap()942 int Splash::getLineCap() {
943 return state->lineCap;
944 }
945
getLineJoin()946 int Splash::getLineJoin() {
947 return state->lineJoin;
948 }
949
getMiterLimit()950 SplashCoord Splash::getMiterLimit() {
951 return state->miterLimit;
952 }
953
getFlatness()954 SplashCoord Splash::getFlatness() {
955 return state->flatness;
956 }
957
getLineDash()958 SplashCoord *Splash::getLineDash() {
959 return state->lineDash;
960 }
961
getLineDashLength()962 int Splash::getLineDashLength() {
963 return state->lineDashLength;
964 }
965
getLineDashPhase()966 SplashCoord Splash::getLineDashPhase() {
967 return state->lineDashPhase;
968 }
969
getClip()970 SplashClip *Splash::getClip() {
971 return state->clip;
972 }
973
getSoftMask()974 SplashBitmap *Splash::getSoftMask() {
975 return state->softMask;
976 }
977
getInNonIsolatedGroup()978 GBool Splash::getInNonIsolatedGroup() {
979 return state->inNonIsolatedGroup;
980 }
981
982 //------------------------------------------------------------------------
983 // state write
984 //------------------------------------------------------------------------
985
setMatrix(SplashCoord * matrix)986 void Splash::setMatrix(SplashCoord *matrix) {
987 memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
988 }
989
setStrokePattern(SplashPattern * strokePattern)990 void Splash::setStrokePattern(SplashPattern *strokePattern) {
991 state->setStrokePattern(strokePattern);
992 }
993
setFillPattern(SplashPattern * fillPattern)994 void Splash::setFillPattern(SplashPattern *fillPattern) {
995 state->setFillPattern(fillPattern);
996 }
997
setScreen(SplashScreen * screen)998 void Splash::setScreen(SplashScreen *screen) {
999 state->setScreen(screen);
1000 }
1001
setBlendFunc(SplashBlendFunc func)1002 void Splash::setBlendFunc(SplashBlendFunc func) {
1003 state->blendFunc = func;
1004 }
1005
setStrokeAlpha(SplashCoord alpha)1006 void Splash::setStrokeAlpha(SplashCoord alpha) {
1007 state->strokeAlpha = alpha;
1008 }
1009
setFillAlpha(SplashCoord alpha)1010 void Splash::setFillAlpha(SplashCoord alpha) {
1011 state->fillAlpha = alpha;
1012 }
1013
setLineWidth(SplashCoord lineWidth)1014 void Splash::setLineWidth(SplashCoord lineWidth) {
1015 state->lineWidth = lineWidth;
1016 }
1017
setLineCap(int lineCap)1018 void Splash::setLineCap(int lineCap) {
1019 state->lineCap = lineCap;
1020 }
1021
setLineJoin(int lineJoin)1022 void Splash::setLineJoin(int lineJoin) {
1023 state->lineJoin = lineJoin;
1024 }
1025
setMiterLimit(SplashCoord miterLimit)1026 void Splash::setMiterLimit(SplashCoord miterLimit) {
1027 state->miterLimit = miterLimit;
1028 }
1029
setFlatness(SplashCoord flatness)1030 void Splash::setFlatness(SplashCoord flatness) {
1031 if (flatness < 1) {
1032 state->flatness = 1;
1033 } else {
1034 state->flatness = flatness;
1035 }
1036 }
1037
setLineDash(SplashCoord * lineDash,int lineDashLength,SplashCoord lineDashPhase)1038 void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
1039 SplashCoord lineDashPhase) {
1040 state->setLineDash(lineDash, lineDashLength, lineDashPhase);
1041 }
1042
setStrokeAdjust(GBool strokeAdjust)1043 void Splash::setStrokeAdjust(GBool strokeAdjust) {
1044 state->strokeAdjust = strokeAdjust;
1045 }
1046
clipResetToRect(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1)1047 void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
1048 SplashCoord x1, SplashCoord y1) {
1049 state->clip->resetToRect(x0, y0, x1, y1);
1050 }
1051
clipToRect(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1)1052 SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
1053 SplashCoord x1, SplashCoord y1) {
1054 return state->clip->clipToRect(x0, y0, x1, y1);
1055 }
1056
clipToPath(SplashPath * path,GBool eo)1057 SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
1058 return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
1059 }
1060
setSoftMask(SplashBitmap * softMask)1061 void Splash::setSoftMask(SplashBitmap *softMask) {
1062 state->setSoftMask(softMask);
1063 }
1064
setInNonIsolatedGroup(SplashBitmap * alpha0BitmapA,int alpha0XA,int alpha0YA)1065 void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
1066 int alpha0XA, int alpha0YA) {
1067 alpha0Bitmap = alpha0BitmapA;
1068 alpha0X = alpha0XA;
1069 alpha0Y = alpha0YA;
1070 state->inNonIsolatedGroup = gTrue;
1071 }
1072
1073 //------------------------------------------------------------------------
1074 // state save/restore
1075 //------------------------------------------------------------------------
1076
saveState()1077 void Splash::saveState() {
1078 SplashState *newState;
1079
1080 newState = state->copy();
1081 newState->next = state;
1082 state = newState;
1083 }
1084
restoreState()1085 SplashError Splash::restoreState() {
1086 SplashState *oldState;
1087
1088 if (!state->next) {
1089 return splashErrNoSave;
1090 }
1091 oldState = state;
1092 state = state->next;
1093 delete oldState;
1094 return splashOk;
1095 }
1096
1097 //------------------------------------------------------------------------
1098 // drawing operations
1099 //------------------------------------------------------------------------
1100
clear(SplashColorPtr color,Guchar alpha)1101 void Splash::clear(SplashColorPtr color, Guchar alpha) {
1102 SplashColorPtr row, p;
1103 Guchar mono;
1104 int x, y;
1105
1106 switch (bitmap->mode) {
1107 case splashModeMono1:
1108 mono = (color[0] & 0x80) ? 0xff : 0x00;
1109 if (bitmap->rowSize < 0) {
1110 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1111 mono, -bitmap->rowSize * bitmap->height);
1112 } else {
1113 memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
1114 }
1115 break;
1116 case splashModeMono8:
1117 if (bitmap->rowSize < 0) {
1118 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1119 color[0], -bitmap->rowSize * bitmap->height);
1120 } else {
1121 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1122 }
1123 break;
1124 case splashModeRGB8:
1125 if (color[0] == color[1] && color[1] == color[2]) {
1126 if (bitmap->rowSize < 0) {
1127 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1128 color[0], -bitmap->rowSize * bitmap->height);
1129 } else {
1130 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1131 }
1132 } else {
1133 row = bitmap->data;
1134 for (y = 0; y < bitmap->height; ++y) {
1135 p = row;
1136 for (x = 0; x < bitmap->width; ++x) {
1137 *p++ = color[2];
1138 *p++ = color[1];
1139 *p++ = color[0];
1140 }
1141 row += bitmap->rowSize;
1142 }
1143 }
1144 break;
1145 case splashModeXBGR8:
1146 if (color[0] == color[1] && color[1] == color[2]) {
1147 if (bitmap->rowSize < 0) {
1148 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1149 color[0], -bitmap->rowSize * bitmap->height);
1150 } else {
1151 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1152 }
1153 } else {
1154 row = bitmap->data;
1155 for (y = 0; y < bitmap->height; ++y) {
1156 p = row;
1157 for (x = 0; x < bitmap->width; ++x) {
1158 *p++ = color[0];
1159 *p++ = color[1];
1160 *p++ = color[2];
1161 *p++ = 255;
1162 }
1163 row += bitmap->rowSize;
1164 }
1165 }
1166 break;
1167 case splashModeBGR8:
1168 if (color[0] == color[1] && color[1] == color[2]) {
1169 if (bitmap->rowSize < 0) {
1170 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1171 color[0], -bitmap->rowSize * bitmap->height);
1172 } else {
1173 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1174 }
1175 } else {
1176 row = bitmap->data;
1177 for (y = 0; y < bitmap->height; ++y) {
1178 p = row;
1179 for (x = 0; x < bitmap->width; ++x) {
1180 *p++ = color[0];
1181 *p++ = color[1];
1182 *p++ = color[2];
1183 }
1184 row += bitmap->rowSize;
1185 }
1186 }
1187 break;
1188 #if SPLASH_CMYK
1189 case splashModeCMYK8:
1190 if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
1191 if (bitmap->rowSize < 0) {
1192 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1193 color[0], -bitmap->rowSize * bitmap->height);
1194 } else {
1195 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1196 }
1197 } else {
1198 row = bitmap->data;
1199 for (y = 0; y < bitmap->height; ++y) {
1200 p = row;
1201 for (x = 0; x < bitmap->width; ++x) {
1202 *p++ = color[0];
1203 *p++ = color[1];
1204 *p++ = color[2];
1205 *p++ = color[3];
1206 }
1207 row += bitmap->rowSize;
1208 }
1209 }
1210 break;
1211 #endif
1212 }
1213
1214 if (bitmap->alpha) {
1215 memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
1216 }
1217
1218 updateModX(0);
1219 updateModY(0);
1220 updateModX(bitmap->width - 1);
1221 updateModY(bitmap->height - 1);
1222 }
1223
stroke(SplashPath * path)1224 SplashError Splash::stroke(SplashPath *path) {
1225 SplashPath *path2, *dPath;
1226
1227 if (debugMode) {
1228 printf("stroke [dash:%d] [width:%.2f]:\n",
1229 state->lineDashLength, (double)state->lineWidth);
1230 dumpPath(path);
1231 }
1232 opClipRes = splashClipAllOutside;
1233 if (path->length == 0) {
1234 return splashErrEmptyPath;
1235 }
1236 path2 = flattenPath(path, state->matrix, state->flatness);
1237 if (state->lineDashLength > 0) {
1238 dPath = makeDashedPath(path2);
1239 delete path2;
1240 path2 = dPath;
1241 }
1242 if (state->lineWidth == 0) {
1243 strokeNarrow(path2);
1244 } else {
1245 strokeWide(path2);
1246 }
1247 delete path2;
1248 return splashOk;
1249 }
1250
strokeNarrow(SplashPath * path)1251 void Splash::strokeNarrow(SplashPath *path) {
1252 SplashPipe pipe;
1253 SplashXPath *xPath;
1254 SplashXPathSeg *seg;
1255 int x0, x1, x2, x3, y0, y1, x, y, t;
1256 SplashCoord dx, dy, dxdy;
1257 SplashClipResult clipRes;
1258 int nClipRes[3];
1259 int i;
1260
1261 nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
1262
1263 xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
1264
1265 pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha,
1266 gFalse, gFalse);
1267
1268 for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
1269
1270 x0 = splashFloor(seg->x0);
1271 x1 = splashFloor(seg->x1);
1272 y0 = splashFloor(seg->y0);
1273 y1 = splashFloor(seg->y1);
1274
1275 // horizontal segment
1276 if (y0 == y1) {
1277 if (x0 > x1) {
1278 t = x0; x0 = x1; x1 = t;
1279 }
1280 if ((clipRes = state->clip->testSpan(x0, x1, y0))
1281 != splashClipAllOutside) {
1282 drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
1283 }
1284
1285 // segment with |dx| > |dy|
1286 } else if (splashAbs(seg->dxdy) > 1) {
1287 dx = seg->x1 - seg->x0;
1288 dy = seg->y1 - seg->y0;
1289 dxdy = seg->dxdy;
1290 if (y0 > y1) {
1291 t = y0; y0 = y1; y1 = t;
1292 t = x0; x0 = x1; x1 = t;
1293 dx = -dx;
1294 dy = -dy;
1295 }
1296 if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
1297 x0 <= x1 ? x1 : x0, y1))
1298 != splashClipAllOutside) {
1299 if (dx > 0) {
1300 x2 = x0;
1301 x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
1302 drawSpan(&pipe, x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0,
1303 clipRes == splashClipAllInside);
1304 x2 = x3;
1305 for (y = y0 + 1; y <= y1 - 1; ++y) {
1306 x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
1307 drawSpan(&pipe, x2, x3 - 1, y, clipRes == splashClipAllInside);
1308 x2 = x3;
1309 }
1310 drawSpan(&pipe, x2, x2 <= x1 ? x1 : x2, y1,
1311 clipRes == splashClipAllInside);
1312 } else {
1313 x2 = x0;
1314 x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
1315 drawSpan(&pipe, (x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0,
1316 clipRes == splashClipAllInside);
1317 x2 = x3;
1318 for (y = y0 + 1; y <= y1 - 1; ++y) {
1319 x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
1320 drawSpan(&pipe, x3 + 1, x2, y, clipRes == splashClipAllInside);
1321 x2 = x3;
1322 }
1323 drawSpan(&pipe, x1, (x1 <= x2) ? x2 : x1, y1,
1324 clipRes == splashClipAllInside);
1325 }
1326 }
1327
1328 // segment with |dy| > |dx|
1329 } else {
1330 dxdy = seg->dxdy;
1331 if (y0 > y1) {
1332 t = x0; x0 = x1; x1 = t;
1333 t = y0; y0 = y1; y1 = t;
1334 }
1335 if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
1336 x0 <= x1 ? x1 : x0, y1))
1337 != splashClipAllOutside) {
1338 drawPixel(&pipe, x0, y0, clipRes == splashClipAllInside);
1339 for (y = y0 + 1; y <= y1 - 1; ++y) {
1340 x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
1341 drawPixel(&pipe, x, y, clipRes == splashClipAllInside);
1342 }
1343 drawPixel(&pipe, x1, y1, clipRes == splashClipAllInside);
1344 }
1345 }
1346 ++nClipRes[clipRes];
1347 }
1348 if (nClipRes[splashClipPartial] ||
1349 (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
1350 opClipRes = splashClipPartial;
1351 } else if (nClipRes[splashClipAllInside]) {
1352 opClipRes = splashClipAllInside;
1353 } else {
1354 opClipRes = splashClipAllOutside;
1355 }
1356
1357 delete xPath;
1358 }
1359
strokeWide(SplashPath * path)1360 void Splash::strokeWide(SplashPath *path) {
1361 SplashPath *path2;
1362
1363 path2 = makeStrokePath(path, gFalse);
1364 fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
1365 delete path2;
1366 }
1367
flattenPath(SplashPath * path,SplashCoord * matrix,SplashCoord flatness)1368 SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
1369 SplashCoord flatness) {
1370 SplashPath *fPath;
1371 SplashCoord flatness2;
1372 Guchar flag;
1373 int i;
1374
1375 fPath = new SplashPath();
1376 flatness2 = flatness * flatness;
1377 i = 0;
1378 while (i < path->length) {
1379 flag = path->flags[i];
1380 if (flag & splashPathFirst) {
1381 fPath->moveTo(path->pts[i].x, path->pts[i].y);
1382 ++i;
1383 } else {
1384 if (flag & splashPathCurve) {
1385 flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
1386 path->pts[i ].x, path->pts[i ].y,
1387 path->pts[i+1].x, path->pts[i+1].y,
1388 path->pts[i+2].x, path->pts[i+2].y,
1389 matrix, flatness2, fPath);
1390 i += 3;
1391 } else {
1392 fPath->lineTo(path->pts[i].x, path->pts[i].y);
1393 ++i;
1394 }
1395 if (path->flags[i-1] & splashPathClosed) {
1396 fPath->close();
1397 }
1398 }
1399 }
1400 return fPath;
1401 }
1402
flattenCurve(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1,SplashCoord x2,SplashCoord y2,SplashCoord x3,SplashCoord y3,SplashCoord * matrix,SplashCoord flatness2,SplashPath * fPath)1403 void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
1404 SplashCoord x1, SplashCoord y1,
1405 SplashCoord x2, SplashCoord y2,
1406 SplashCoord x3, SplashCoord y3,
1407 SplashCoord *matrix, SplashCoord flatness2,
1408 SplashPath *fPath) {
1409 SplashCoord cx[splashMaxCurveSplits + 1][3];
1410 SplashCoord cy[splashMaxCurveSplits + 1][3];
1411 int cNext[splashMaxCurveSplits + 1];
1412 SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
1413 SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
1414 SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
1415 int p1, p2, p3;
1416
1417 // initial segment
1418 p1 = 0;
1419 p2 = splashMaxCurveSplits;
1420 cx[p1][0] = x0; cy[p1][0] = y0;
1421 cx[p1][1] = x1; cy[p1][1] = y1;
1422 cx[p1][2] = x2; cy[p1][2] = y2;
1423 cx[p2][0] = x3; cy[p2][0] = y3;
1424 cNext[p1] = p2;
1425
1426 while (p1 < splashMaxCurveSplits) {
1427
1428 // get the next segment
1429 xl0 = cx[p1][0]; yl0 = cy[p1][0];
1430 xx1 = cx[p1][1]; yy1 = cy[p1][1];
1431 xx2 = cx[p1][2]; yy2 = cy[p1][2];
1432 p2 = cNext[p1];
1433 xr3 = cx[p2][0]; yr3 = cy[p2][0];
1434
1435 // compute the distances (in device space) from the control points
1436 // to the midpoint of the straight line (this is a bit of a hack,
1437 // but it's much faster than computing the actual distances to the
1438 // line)
1439 transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
1440 transform(matrix, xx1, yy1, &tx, &ty);
1441 dx = tx - mx;
1442 dy = ty - my;
1443 d1 = dx*dx + dy*dy;
1444 transform(matrix, xx2, yy2, &tx, &ty);
1445 dx = tx - mx;
1446 dy = ty - my;
1447 d2 = dx*dx + dy*dy;
1448
1449 // if the curve is flat enough, or no more subdivisions are
1450 // allowed, add the straight line segment
1451 if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
1452 fPath->lineTo(xr3, yr3);
1453 p1 = p2;
1454
1455 // otherwise, subdivide the curve
1456 } else {
1457 xl1 = (xl0 + xx1) * 0.5;
1458 yl1 = (yl0 + yy1) * 0.5;
1459 xh = (xx1 + xx2) * 0.5;
1460 yh = (yy1 + yy2) * 0.5;
1461 xl2 = (xl1 + xh) * 0.5;
1462 yl2 = (yl1 + yh) * 0.5;
1463 xr2 = (xx2 + xr3) * 0.5;
1464 yr2 = (yy2 + yr3) * 0.5;
1465 xr1 = (xh + xr2) * 0.5;
1466 yr1 = (yh + yr2) * 0.5;
1467 xr0 = (xl2 + xr1) * 0.5;
1468 yr0 = (yl2 + yr1) * 0.5;
1469 // add the new subdivision points
1470 p3 = (p1 + p2) / 2;
1471 cx[p1][1] = xl1; cy[p1][1] = yl1;
1472 cx[p1][2] = xl2; cy[p1][2] = yl2;
1473 cNext[p1] = p3;
1474 cx[p3][0] = xr0; cy[p3][0] = yr0;
1475 cx[p3][1] = xr1; cy[p3][1] = yr1;
1476 cx[p3][2] = xr2; cy[p3][2] = yr2;
1477 cNext[p3] = p2;
1478 }
1479 }
1480 }
1481
makeDashedPath(SplashPath * path)1482 SplashPath *Splash::makeDashedPath(SplashPath *path) {
1483 SplashPath *dPath;
1484 SplashCoord lineDashTotal;
1485 SplashCoord lineDashStartPhase, lineDashDist, segLen;
1486 SplashCoord x0, y0, x1, y1, xa, ya;
1487 GBool lineDashStartOn, lineDashOn, newPath;
1488 int lineDashStartIdx, lineDashIdx;
1489 int i, j, k;
1490
1491 lineDashTotal = 0;
1492 for (i = 0; i < state->lineDashLength; ++i) {
1493 lineDashTotal += state->lineDash[i];
1494 }
1495 lineDashStartPhase = state->lineDashPhase;
1496 i = splashFloor(lineDashStartPhase / lineDashTotal);
1497 lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
1498 lineDashStartOn = gTrue;
1499 lineDashStartIdx = 0;
1500 while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
1501 lineDashStartOn = !lineDashStartOn;
1502 lineDashStartPhase -= state->lineDash[lineDashStartIdx];
1503 ++lineDashStartIdx;
1504 }
1505
1506 dPath = new SplashPath();
1507
1508 // process each subpath
1509 i = 0;
1510 while (i < path->length) {
1511
1512 // find the end of the subpath
1513 for (j = i;
1514 j < path->length - 1 && !(path->flags[j] & splashPathLast);
1515 ++j) ;
1516
1517 // initialize the dash parameters
1518 lineDashOn = lineDashStartOn;
1519 lineDashIdx = lineDashStartIdx;
1520 lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
1521
1522 // process each segment of the subpath
1523 newPath = gTrue;
1524 for (k = i; k < j; ++k) {
1525
1526 // grab the segment
1527 x0 = path->pts[k].x;
1528 y0 = path->pts[k].y;
1529 x1 = path->pts[k+1].x;
1530 y1 = path->pts[k+1].y;
1531 segLen = splashDist(x0, y0, x1, y1);
1532
1533 // process the segment
1534 while (segLen > 0) {
1535
1536 if (lineDashDist >= segLen) {
1537 if (lineDashOn) {
1538 if (newPath) {
1539 dPath->moveTo(x0, y0);
1540 newPath = gFalse;
1541 }
1542 dPath->lineTo(x1, y1);
1543 }
1544 lineDashDist -= segLen;
1545 segLen = 0;
1546
1547 } else {
1548 xa = x0 + (lineDashDist / segLen) * (x1 - x0);
1549 ya = y0 + (lineDashDist / segLen) * (y1 - y0);
1550 if (lineDashOn) {
1551 if (newPath) {
1552 dPath->moveTo(x0, y0);
1553 newPath = gFalse;
1554 }
1555 dPath->lineTo(xa, ya);
1556 }
1557 x0 = xa;
1558 y0 = ya;
1559 segLen -= lineDashDist;
1560 lineDashDist = 0;
1561 }
1562
1563 // get the next entry in the dash array
1564 if (lineDashDist <= 0) {
1565 lineDashOn = !lineDashOn;
1566 if (++lineDashIdx == state->lineDashLength) {
1567 lineDashIdx = 0;
1568 }
1569 lineDashDist = state->lineDash[lineDashIdx];
1570 newPath = gTrue;
1571 }
1572 }
1573 }
1574 i = j + 1;
1575 }
1576
1577 return dPath;
1578 }
1579
fill(SplashPath * path,GBool eo)1580 SplashError Splash::fill(SplashPath *path, GBool eo) {
1581 if (debugMode) {
1582 printf("fill [eo:%d]:\n", eo);
1583 dumpPath(path);
1584 }
1585 return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
1586 }
1587
fillWithPattern(SplashPath * path,GBool eo,SplashPattern * pattern,SplashCoord alpha)1588 SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
1589 SplashPattern *pattern,
1590 SplashCoord alpha) {
1591 SplashPipe pipe;
1592 SplashXPath *xPath;
1593 SplashXPathScanner *scanner;
1594 int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
1595 SplashClipResult clipRes, clipRes2;
1596
1597 if (path->length == 0) {
1598 return splashErrEmptyPath;
1599 }
1600 xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
1601 if (vectorAntialias) {
1602 xPath->aaScale();
1603 }
1604 xPath->sort();
1605 scanner = new SplashXPathScanner(xPath, eo);
1606
1607 // get the min and max x and y values
1608 if (vectorAntialias) {
1609 scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
1610 } else {
1611 scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
1612 }
1613
1614 // check clipping
1615 if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
1616 != splashClipAllOutside) {
1617
1618 // limit the y range
1619 if (yMinI < state->clip->getYMinI()) {
1620 yMinI = state->clip->getYMinI();
1621 }
1622 if (yMaxI > state->clip->getYMaxI()) {
1623 yMaxI = state->clip->getYMaxI();
1624 }
1625
1626 pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse);
1627
1628 // draw the spans
1629 if (vectorAntialias) {
1630 for (y = yMinI; y <= yMaxI; ++y) {
1631 scanner->renderAALine(aaBuf, &x0, &x1, y);
1632 if (clipRes != splashClipAllInside) {
1633 state->clip->clipAALine(aaBuf, &x0, &x1, y);
1634 }
1635 drawAALine(&pipe, x0, x1, y);
1636 }
1637 } else {
1638 for (y = yMinI; y <= yMaxI; ++y) {
1639 while (scanner->getNextSpan(y, &x0, &x1)) {
1640 if (clipRes == splashClipAllInside) {
1641 drawSpan(&pipe, x0, x1, y, gTrue);
1642 } else {
1643 // limit the x range
1644 if (x0 < state->clip->getXMinI()) {
1645 x0 = state->clip->getXMinI();
1646 }
1647 if (x1 > state->clip->getXMaxI()) {
1648 x1 = state->clip->getXMaxI();
1649 }
1650 clipRes2 = state->clip->testSpan(x0, x1, y);
1651 drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
1652 }
1653 }
1654 }
1655 }
1656 }
1657 opClipRes = clipRes;
1658
1659 delete scanner;
1660 delete xPath;
1661 return splashOk;
1662 }
1663
xorFill(SplashPath * path,GBool eo)1664 SplashError Splash::xorFill(SplashPath *path, GBool eo) {
1665 SplashPipe pipe;
1666 SplashXPath *xPath;
1667 SplashXPathScanner *scanner;
1668 int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
1669 SplashClipResult clipRes, clipRes2;
1670 SplashBlendFunc origBlendFunc;
1671
1672 if (path->length == 0) {
1673 return splashErrEmptyPath;
1674 }
1675 xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
1676 xPath->sort();
1677 scanner = new SplashXPathScanner(xPath, eo);
1678
1679 // get the min and max x and y values
1680 scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
1681
1682 // check clipping
1683 if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
1684 != splashClipAllOutside) {
1685
1686 // limit the y range
1687 if (yMinI < state->clip->getYMinI()) {
1688 yMinI = state->clip->getYMinI();
1689 }
1690 if (yMaxI > state->clip->getYMaxI()) {
1691 yMaxI = state->clip->getYMaxI();
1692 }
1693
1694 origBlendFunc = state->blendFunc;
1695 state->blendFunc = &blendXor;
1696 pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse);
1697
1698 // draw the spans
1699 for (y = yMinI; y <= yMaxI; ++y) {
1700 while (scanner->getNextSpan(y, &x0, &x1)) {
1701 if (clipRes == splashClipAllInside) {
1702 drawSpan(&pipe, x0, x1, y, gTrue);
1703 } else {
1704 // limit the x range
1705 if (x0 < state->clip->getXMinI()) {
1706 x0 = state->clip->getXMinI();
1707 }
1708 if (x1 > state->clip->getXMaxI()) {
1709 x1 = state->clip->getXMaxI();
1710 }
1711 clipRes2 = state->clip->testSpan(x0, x1, y);
1712 drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
1713 }
1714 }
1715 }
1716 state->blendFunc = origBlendFunc;
1717 }
1718 opClipRes = clipRes;
1719
1720 delete scanner;
1721 delete xPath;
1722 return splashOk;
1723 }
1724
fillChar(SplashCoord x,SplashCoord y,int c,SplashFont * font)1725 SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
1726 int c, SplashFont *font) {
1727 SplashGlyphBitmap glyph;
1728 SplashCoord xt, yt;
1729 int x0, y0, xFrac, yFrac;
1730 SplashClipResult clipRes;
1731
1732 if (debugMode) {
1733 printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
1734 (double)x, (double)y, c, c, c);
1735 }
1736 transform(state->matrix, x, y, &xt, &yt);
1737 x0 = splashFloor(xt);
1738 xFrac = splashFloor((xt - x0) * splashFontFraction);
1739 y0 = splashFloor(yt);
1740 yFrac = splashFloor((yt - y0) * splashFontFraction);
1741 if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) {
1742 return splashErrNoGlyph;
1743 }
1744 if (clipRes != splashClipAllOutside) {
1745 fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside);
1746 }
1747 opClipRes = clipRes;
1748 if (glyph.freeData) {
1749 gfree(glyph.data);
1750 }
1751 return splashOk;
1752 }
1753
fillGlyph(SplashCoord x,SplashCoord y,SplashGlyphBitmap * glyph)1754 void Splash::fillGlyph(SplashCoord x, SplashCoord y,
1755 SplashGlyphBitmap *glyph) {
1756 SplashCoord xt, yt;
1757 int x0, y0;
1758
1759 transform(state->matrix, x, y, &xt, &yt);
1760 x0 = splashFloor(xt);
1761 y0 = splashFloor(yt);
1762 SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x,
1763 y0 - glyph->y,
1764 x0 - glyph->x + glyph->w - 1,
1765 y0 - glyph->y + glyph->h - 1);
1766 if (clipRes != splashClipAllOutside) {
1767 fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside);
1768 }
1769 opClipRes = clipRes;
1770 }
1771
fillGlyph2(int x0,int y0,SplashGlyphBitmap * glyph,GBool noClip)1772 void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
1773 SplashPipe pipe;
1774 int alpha0, alpha;
1775 Guchar *p;
1776 int x1, y1, xx, xx1, yy;
1777
1778 p = glyph->data;
1779 int xStart = x0 - glyph->x;
1780 int yStart = y0 - glyph->y;
1781 int xxLimit = glyph->w;
1782 int yyLimit = glyph->h;
1783
1784 if (yStart < 0)
1785 {
1786 p += glyph->w * -yStart; // move p to the beginning of the first painted row
1787 yyLimit += yStart;
1788 yStart = 0;
1789 }
1790
1791 if (xStart < 0)
1792 {
1793 p += -xStart; // move p to the first painted pixel
1794 xxLimit += xStart;
1795 xStart = 0;
1796 }
1797
1798 if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart;
1799 if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart;
1800
1801 if (noClip) {
1802 if (glyph->aa) {
1803 pipeInit(&pipe, xStart, yStart,
1804 state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
1805 for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1806 pipeSetXY(&pipe, xStart, y1);
1807 for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
1808 alpha = p[xx];
1809 if (alpha != 0) {
1810 pipe.shape = (SplashCoord)(alpha / 255.0);
1811 pipeRun(&pipe);
1812 updateModX(x1);
1813 updateModY(y1);
1814 } else {
1815 pipeIncX(&pipe);
1816 }
1817 }
1818 p += glyph->w;
1819 }
1820 } else {
1821 const int widthEight = splashCeil(glyph->w / 8.0);
1822
1823 pipeInit(&pipe, xStart, yStart,
1824 state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
1825 for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1826 pipeSetXY(&pipe, xStart, y1);
1827 for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
1828 alpha0 = p[xx / 8];
1829 for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
1830 if (alpha0 & 0x80) {
1831 pipeRun(&pipe);
1832 updateModX(x1);
1833 updateModY(y1);
1834 } else {
1835 pipeIncX(&pipe);
1836 }
1837 alpha0 <<= 1;
1838 }
1839 }
1840 p += widthEight;
1841 }
1842 }
1843 } else {
1844 if (glyph->aa) {
1845 pipeInit(&pipe, xStart, yStart,
1846 state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
1847 for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1848 pipeSetXY(&pipe, xStart, y1);
1849 for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
1850 if (state->clip->test(x1, y1)) {
1851 alpha = p[xx];
1852 if (alpha != 0) {
1853 pipe.shape = (SplashCoord)(alpha / 255.0);
1854 pipeRun(&pipe);
1855 updateModX(x1);
1856 updateModY(y1);
1857 } else {
1858 pipeIncX(&pipe);
1859 }
1860 } else {
1861 pipeIncX(&pipe);
1862 }
1863 }
1864 p += glyph->w;
1865 }
1866 } else {
1867 const int widthEight = splashCeil(glyph->w / 8.0);
1868
1869 pipeInit(&pipe, xStart, yStart,
1870 state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
1871 for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1872 pipeSetXY(&pipe, xStart, y1);
1873 for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
1874 alpha0 = p[xx / 8];
1875 for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
1876 if (state->clip->test(x1, y1)) {
1877 if (alpha0 & 0x80) {
1878 pipeRun(&pipe);
1879 updateModX(x1);
1880 updateModY(y1);
1881 } else {
1882 pipeIncX(&pipe);
1883 }
1884 } else {
1885 pipeIncX(&pipe);
1886 }
1887 alpha0 <<= 1;
1888 }
1889 }
1890 p += widthEight;
1891 }
1892 }
1893 }
1894 }
1895
fillImageMask(SplashImageMaskSource src,void * srcData,int w,int h,SplashCoord * mat,GBool glyphMode)1896 SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
1897 int w, int h, SplashCoord *mat,
1898 GBool glyphMode) {
1899 SplashPipe pipe;
1900 GBool rot;
1901 SplashCoord xScale, yScale, xShear, yShear, yShear1;
1902 int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
1903 int ulx, uly, llx, lly, urx, ury, lrx, lry;
1904 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
1905 int xMin, xMax, yMin, yMax;
1906 SplashClipResult clipRes, clipRes2;
1907 int yp, yq, yt, yStep, lastYStep;
1908 int xp, xq, xt, xStep, xSrc;
1909 int k1, spanXMin, spanXMax, spanY;
1910 SplashColorPtr pixBuf, p;
1911 int pixAcc;
1912 int x, y, x1, x2, y2;
1913 SplashCoord y1;
1914 int n, m, i, j;
1915
1916 if (debugMode) {
1917 printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
1918 w, h, (double)mat[0], (double)mat[1], (double)mat[2],
1919 (double)mat[3], (double)mat[4], (double)mat[5]);
1920 }
1921
1922 if (w == 0 && h == 0) return splashErrZeroImage;
1923
1924 // check for singular matrix
1925 if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
1926 return splashErrSingularMatrix;
1927 }
1928
1929 // compute scale, shear, rotation, translation parameters
1930 rot = splashAbs(mat[1]) > splashAbs(mat[0]);
1931 if (rot) {
1932 xScale = -mat[1];
1933 yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
1934 xShear = -mat[3] / yScale;
1935 yShear = -mat[0] / mat[1];
1936 } else {
1937 xScale = mat[0];
1938 yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
1939 xShear = mat[2] / yScale;
1940 yShear = mat[1] / mat[0];
1941 }
1942 // Note 1: The PDF spec says that all pixels whose *centers* lie
1943 // within the region get painted -- but that doesn't seem to match
1944 // up with what Acrobat actually does: it ends up leaving gaps
1945 // between image stripes. So we use the same rule here as for
1946 // fills: any pixel that overlaps the region gets painted.
1947 // Note 2: The "glyphMode" flag is a kludge: it switches back to
1948 // "correct" behavior (matching the spec), for use in rendering Type
1949 // 3 fonts.
1950 // Note 3: The +/-0.01 in these computations is to avoid floating
1951 // point precision problems which can lead to gaps between image
1952 // stripes (it can cause image stripes to overlap, but that's a much
1953 // less visible problem).
1954 if (glyphMode) {
1955 if (xScale >= 0) {
1956 tx = splashRound(mat[4]);
1957 tx2 = splashRound(mat[4] + xScale) - 1;
1958 } else {
1959 tx = splashRound(mat[4]) - 1;
1960 tx2 = splashRound(mat[4] + xScale);
1961 }
1962 } else {
1963 if (xScale >= 0) {
1964 tx = splashFloor(mat[4] - 0.01);
1965 tx2 = splashFloor(mat[4] + xScale + 0.01);
1966 } else {
1967 tx = splashFloor(mat[4] + 0.01);
1968 tx2 = splashFloor(mat[4] + xScale - 0.01);
1969 }
1970 }
1971 scaledWidth = abs(tx2 - tx) + 1;
1972 if (glyphMode) {
1973 if (yScale >= 0) {
1974 ty = splashRound(mat[5]);
1975 ty2 = splashRound(mat[5] + yScale) - 1;
1976 } else {
1977 ty = splashRound(mat[5]) - 1;
1978 ty2 = splashRound(mat[5] + yScale);
1979 }
1980 } else {
1981 if (yScale >= 0) {
1982 ty = splashFloor(mat[5] - 0.01);
1983 ty2 = splashFloor(mat[5] + yScale + 0.01);
1984 } else {
1985 ty = splashFloor(mat[5] + 0.01);
1986 ty2 = splashFloor(mat[5] + yScale - 0.01);
1987 }
1988 }
1989 scaledHeight = abs(ty2 - ty) + 1;
1990 xSign = (xScale < 0) ? -1 : 1;
1991 ySign = (yScale < 0) ? -1 : 1;
1992 yShear1 = (SplashCoord)xSign * yShear;
1993
1994 // clipping
1995 ulx1 = 0;
1996 uly1 = 0;
1997 urx1 = xSign * (scaledWidth - 1);
1998 ury1 = (int)(yShear * urx1);
1999 llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2000 lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2001 lrx1 = xSign * (scaledWidth - 1) +
2002 splashRound(xShear * ySign * (scaledHeight - 1));
2003 lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2004 if (rot) {
2005 ulx = tx + uly1; uly = ty - ulx1;
2006 urx = tx + ury1; ury = ty - urx1;
2007 llx = tx + lly1; lly = ty - llx1;
2008 lrx = tx + lry1; lry = ty - lrx1;
2009 } else {
2010 ulx = tx + ulx1; uly = ty + uly1;
2011 urx = tx + urx1; ury = ty + ury1;
2012 llx = tx + llx1; lly = ty + lly1;
2013 lrx = tx + lrx1; lry = ty + lry1;
2014 }
2015 xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2016 : (llx < lrx) ? llx : lrx
2017 : (urx < llx) ? (urx < lrx) ? urx : lrx
2018 : (llx < lrx) ? llx : lrx;
2019 xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2020 : (llx > lrx) ? llx : lrx
2021 : (urx > llx) ? (urx > lrx) ? urx : lrx
2022 : (llx > lrx) ? llx : lrx;
2023 yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2024 : (lly < lry) ? lly : lry
2025 : (ury < lly) ? (ury < lry) ? ury : lry
2026 : (lly < lry) ? lly : lry;
2027 yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2028 : (lly > lry) ? lly : lry
2029 : (ury > lly) ? (ury > lry) ? ury : lry
2030 : (lly > lry) ? lly : lry;
2031 clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2032 opClipRes = clipRes;
2033
2034 // compute Bresenham parameters for x and y scaling
2035 yp = h / scaledHeight;
2036 yq = h % scaledHeight;
2037 xp = w / scaledWidth;
2038 xq = w % scaledWidth;
2039
2040 // allocate pixel buffer
2041 if (yp < 0 || yp > INT_MAX - 1) {
2042 return splashErrBadArg;
2043 }
2044 pixBuf = (SplashColorPtr)gmallocn((yp + 1), w);
2045
2046 // initialize the pixel pipe
2047 pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
2048 gTrue, gFalse);
2049 if (vectorAntialias) {
2050 drawAAPixelInit();
2051 }
2052
2053 // init y scale Bresenham
2054 yt = 0;
2055 lastYStep = 1;
2056
2057 for (y = 0; y < scaledHeight; ++y) {
2058
2059 // y scale Bresenham
2060 yStep = yp;
2061 yt += yq;
2062 if (yt >= scaledHeight) {
2063 yt -= scaledHeight;
2064 ++yStep;
2065 }
2066
2067 // read row(s) from image
2068 n = (yp > 0) ? yStep : lastYStep;
2069 if (n > 0) {
2070 p = pixBuf;
2071 for (i = 0; i < n; ++i) {
2072 (*src)(srcData, p);
2073 p += w;
2074 }
2075 }
2076 lastYStep = yStep;
2077
2078 // loop-invariant constants
2079 k1 = splashRound(xShear * ySign * y);
2080
2081 // clipping test
2082 if (clipRes != splashClipAllInside &&
2083 !rot &&
2084 (int)(yShear * k1) ==
2085 (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2086 if (xSign > 0) {
2087 spanXMin = tx + k1;
2088 spanXMax = spanXMin + (scaledWidth - 1);
2089 } else {
2090 spanXMax = tx + k1;
2091 spanXMin = spanXMax - (scaledWidth - 1);
2092 }
2093 spanY = ty + ySign * y + (int)(yShear * k1);
2094 clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2095 if (clipRes2 == splashClipAllOutside) {
2096 continue;
2097 }
2098 } else {
2099 clipRes2 = clipRes;
2100 }
2101
2102 // init x scale Bresenham
2103 xt = 0;
2104 xSrc = 0;
2105
2106 // x shear
2107 x1 = k1;
2108
2109 // y shear
2110 y1 = (SplashCoord)ySign * y + yShear * x1;
2111 // this is a kludge: if yShear1 is negative, then (int)y1 would
2112 // change immediately after the first pixel, which is not what we
2113 // want
2114 if (yShear1 < 0) {
2115 y1 += 0.999;
2116 }
2117
2118 // loop-invariant constants
2119 n = yStep > 0 ? yStep : 1;
2120
2121 for (x = 0; x < scaledWidth; ++x) {
2122
2123 // x scale Bresenham
2124 xStep = xp;
2125 xt += xq;
2126 if (xt >= scaledWidth) {
2127 xt -= scaledWidth;
2128 ++xStep;
2129 }
2130
2131 // rotation
2132 if (rot) {
2133 x2 = (int)y1;
2134 y2 = -x1;
2135 } else {
2136 x2 = x1;
2137 y2 = (int)y1;
2138 }
2139
2140 // compute the alpha value for (x,y) after the x and y scaling
2141 // operations
2142 m = xStep > 0 ? xStep : 1;
2143 p = pixBuf + xSrc;
2144 pixAcc = 0;
2145 for (i = 0; i < n; ++i) {
2146 for (j = 0; j < m; ++j) {
2147 pixAcc += *p++;
2148 }
2149 p += w - m;
2150 }
2151
2152 // blend fill color with background
2153 if (pixAcc != 0) {
2154 pipe.shape = (pixAcc == n * m)
2155 ? (SplashCoord)1
2156 : (SplashCoord)pixAcc / (SplashCoord)(n * m);
2157 if (vectorAntialias && clipRes2 != splashClipAllInside) {
2158 drawAAPixel(&pipe, tx + x2, ty + y2);
2159 } else {
2160 drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
2161 }
2162 }
2163
2164 // x scale Bresenham
2165 xSrc += xStep;
2166
2167 // x shear
2168 x1 += xSign;
2169
2170 // y shear
2171 y1 += yShear1;
2172 }
2173 }
2174
2175 // free memory
2176 gfree(pixBuf);
2177
2178 return splashOk;
2179 }
2180
drawImage(SplashImageSource src,void * srcData,SplashColorMode srcMode,GBool srcAlpha,int w,int h,SplashCoord * mat)2181 SplashError Splash::drawImage(SplashImageSource src, void *srcData,
2182 SplashColorMode srcMode, GBool srcAlpha,
2183 int w, int h, SplashCoord *mat) {
2184 SplashPipe pipe;
2185 GBool ok, rot;
2186 SplashCoord xScale, yScale, xShear, yShear, yShear1;
2187 int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
2188 int ulx, uly, llx, lly, urx, ury, lrx, lry;
2189 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2190 int xMin, xMax, yMin, yMax;
2191 SplashClipResult clipRes, clipRes2;
2192 int yp, yq, yt, yStep, lastYStep;
2193 int xp, xq, xt, xStep, xSrc;
2194 int k1, spanXMin, spanXMax, spanY;
2195 SplashColorPtr colorBuf, p;
2196 SplashColor pix;
2197 Guchar *alphaBuf, *q;
2198 #if SPLASH_CMYK
2199 int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
2200 #else
2201 int pixAcc0, pixAcc1, pixAcc2;
2202 #endif
2203 int alphaAcc;
2204 SplashCoord pixMul, alphaMul, alpha;
2205 int x, y, x1, x2, y2;
2206 SplashCoord y1;
2207 int nComps, n, m, i, j;
2208
2209 if (debugMode) {
2210 printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2211 srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
2212 (double)mat[3], (double)mat[4], (double)mat[5]);
2213 }
2214
2215 // check color modes
2216 ok = gFalse; // make gcc happy
2217 nComps = 0; // make gcc happy
2218 switch (bitmap->mode) {
2219 case splashModeMono1:
2220 case splashModeMono8:
2221 ok = srcMode == splashModeMono8;
2222 nComps = 1;
2223 break;
2224 case splashModeRGB8:
2225 ok = srcMode == splashModeRGB8;
2226 nComps = 3;
2227 break;
2228 case splashModeXBGR8:
2229 ok = srcMode == splashModeXBGR8;
2230 nComps = 4;
2231 break;
2232 case splashModeBGR8:
2233 ok = srcMode == splashModeBGR8;
2234 nComps = 3;
2235 break;
2236 #if SPLASH_CMYK
2237 case splashModeCMYK8:
2238 ok = srcMode == splashModeCMYK8;
2239 nComps = 4;
2240 break;
2241 #endif
2242 }
2243 if (!ok) {
2244 return splashErrModeMismatch;
2245 }
2246
2247 // check for singular matrix
2248 if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
2249 return splashErrSingularMatrix;
2250 }
2251
2252 // compute scale, shear, rotation, translation parameters
2253 rot = splashAbs(mat[1]) > splashAbs(mat[0]);
2254 if (rot) {
2255 xScale = -mat[1];
2256 yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
2257 xShear = -mat[3] / yScale;
2258 yShear = -mat[0] / mat[1];
2259 } else {
2260 xScale = mat[0];
2261 yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
2262 xShear = mat[2] / yScale;
2263 yShear = mat[1] / mat[0];
2264 }
2265 // Note 1: The PDF spec says that all pixels whose *centers* lie
2266 // within the region get painted -- but that doesn't seem to match
2267 // up with what Acrobat actually does: it ends up leaving gaps
2268 // between image stripes. So we use the same rule here as for
2269 // fills: any pixel that overlaps the region gets painted.
2270 // Note 2: The +/-0.01 in these computations is to avoid floating
2271 // point precision problems which can lead to gaps between image
2272 // stripes (it can cause image stripes to overlap, but that's a much
2273 // less visible problem).
2274 if (xScale >= 0) {
2275 tx = splashFloor(mat[4] - 0.01);
2276 tx2 = splashFloor(mat[4] + xScale + 0.01);
2277 } else {
2278 tx = splashFloor(mat[4] + 0.01);
2279 tx2 = splashFloor(mat[4] + xScale - 0.01);
2280 }
2281 scaledWidth = abs(tx2 - tx) + 1;
2282 if (yScale >= 0) {
2283 ty = splashFloor(mat[5] - 0.01);
2284 ty2 = splashFloor(mat[5] + yScale + 0.01);
2285 } else {
2286 ty = splashFloor(mat[5] + 0.01);
2287 ty2 = splashFloor(mat[5] + yScale - 0.01);
2288 }
2289 scaledHeight = abs(ty2 - ty) + 1;
2290 xSign = (xScale < 0) ? -1 : 1;
2291 ySign = (yScale < 0) ? -1 : 1;
2292 yShear1 = (SplashCoord)xSign * yShear;
2293
2294 // clipping
2295 ulx1 = 0;
2296 uly1 = 0;
2297 urx1 = xSign * (scaledWidth - 1);
2298 ury1 = (int)(yShear * urx1);
2299 llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2300 lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2301 lrx1 = xSign * (scaledWidth - 1) +
2302 splashRound(xShear * ySign * (scaledHeight - 1));
2303 lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2304 if (rot) {
2305 ulx = tx + uly1; uly = ty - ulx1;
2306 urx = tx + ury1; ury = ty - urx1;
2307 llx = tx + lly1; lly = ty - llx1;
2308 lrx = tx + lry1; lry = ty - lrx1;
2309 } else {
2310 ulx = tx + ulx1; uly = ty + uly1;
2311 urx = tx + urx1; ury = ty + ury1;
2312 llx = tx + llx1; lly = ty + lly1;
2313 lrx = tx + lrx1; lry = ty + lry1;
2314 }
2315 xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2316 : (llx < lrx) ? llx : lrx
2317 : (urx < llx) ? (urx < lrx) ? urx : lrx
2318 : (llx < lrx) ? llx : lrx;
2319 xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2320 : (llx > lrx) ? llx : lrx
2321 : (urx > llx) ? (urx > lrx) ? urx : lrx
2322 : (llx > lrx) ? llx : lrx;
2323 yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2324 : (lly < lry) ? lly : lry
2325 : (ury < lly) ? (ury < lry) ? ury : lry
2326 : (lly < lry) ? lly : lry;
2327 yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2328 : (lly > lry) ? lly : lry
2329 : (ury > lly) ? (ury > lry) ? ury : lry
2330 : (lly > lry) ? lly : lry;
2331 clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2332 opClipRes = clipRes;
2333 if (clipRes == splashClipAllOutside) {
2334 return splashOk;
2335 }
2336
2337 // compute Bresenham parameters for x and y scaling
2338 yp = h / scaledHeight;
2339 yq = h % scaledHeight;
2340 xp = w / scaledWidth;
2341 xq = w % scaledWidth;
2342
2343 // allocate pixel buffers
2344 if (yp < 0 || yp > INT_MAX - 1) {
2345 return splashErrBadArg;
2346 }
2347 colorBuf = (SplashColorPtr)gmallocn3((yp + 1), w, nComps);
2348 if (srcAlpha) {
2349 alphaBuf = (Guchar *)gmallocn((yp + 1), w);
2350 } else {
2351 alphaBuf = NULL;
2352 }
2353
2354 pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
2355 #if SPLASH_CMYK
2356 pixAcc3 = 0; // make gcc happy
2357 #endif
2358
2359 // initialize the pixel pipe
2360 pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
2361 srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
2362 gFalse);
2363 if (vectorAntialias) {
2364 drawAAPixelInit();
2365 }
2366
2367 if (srcAlpha) {
2368
2369 // init y scale Bresenham
2370 yt = 0;
2371 lastYStep = 1;
2372
2373 for (y = 0; y < scaledHeight; ++y) {
2374
2375 // y scale Bresenham
2376 yStep = yp;
2377 yt += yq;
2378 if (yt >= scaledHeight) {
2379 yt -= scaledHeight;
2380 ++yStep;
2381 }
2382
2383 // read row(s) from image
2384 n = (yp > 0) ? yStep : lastYStep;
2385 if (n > 0) {
2386 p = colorBuf;
2387 q = alphaBuf;
2388 for (i = 0; i < n; ++i) {
2389 (*src)(srcData, p, q);
2390 p += w * nComps;
2391 q += w;
2392 }
2393 }
2394 lastYStep = yStep;
2395
2396 // loop-invariant constants
2397 k1 = splashRound(xShear * ySign * y);
2398
2399 // clipping test
2400 if (clipRes != splashClipAllInside &&
2401 !rot &&
2402 (int)(yShear * k1) ==
2403 (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2404 if (xSign > 0) {
2405 spanXMin = tx + k1;
2406 spanXMax = spanXMin + (scaledWidth - 1);
2407 } else {
2408 spanXMax = tx + k1;
2409 spanXMin = spanXMax - (scaledWidth - 1);
2410 }
2411 spanY = ty + ySign * y + (int)(yShear * k1);
2412 clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2413 if (clipRes2 == splashClipAllOutside) {
2414 continue;
2415 }
2416 } else {
2417 clipRes2 = clipRes;
2418 }
2419
2420 // init x scale Bresenham
2421 xt = 0;
2422 xSrc = 0;
2423
2424 // x shear
2425 x1 = k1;
2426
2427 // y shear
2428 y1 = (SplashCoord)ySign * y + yShear * x1;
2429 // this is a kludge: if yShear1 is negative, then (int)y1 would
2430 // change immediately after the first pixel, which is not what
2431 // we want
2432 if (yShear1 < 0) {
2433 y1 += 0.999;
2434 }
2435
2436 // loop-invariant constants
2437 n = yStep > 0 ? yStep : 1;
2438
2439 switch (srcMode) {
2440
2441 case splashModeMono1:
2442 case splashModeMono8:
2443 for (x = 0; x < scaledWidth; ++x) {
2444
2445 // x scale Bresenham
2446 xStep = xp;
2447 xt += xq;
2448 if (xt >= scaledWidth) {
2449 xt -= scaledWidth;
2450 ++xStep;
2451 }
2452
2453 // rotation
2454 if (rot) {
2455 x2 = (int)y1;
2456 y2 = -x1;
2457 } else {
2458 x2 = x1;
2459 y2 = (int)y1;
2460 }
2461
2462 // compute the filtered pixel at (x,y) after the x and y scaling
2463 // operations
2464 m = xStep > 0 ? xStep : 1;
2465 alphaAcc = 0;
2466 p = colorBuf + xSrc;
2467 q = alphaBuf + xSrc;
2468 pixAcc0 = 0;
2469 for (i = 0; i < n; ++i) {
2470 for (j = 0; j < m; ++j) {
2471 pixAcc0 += *p++;
2472 alphaAcc += *q++;
2473 }
2474 p += w - m;
2475 q += w - m;
2476 }
2477 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2478 alphaMul = pixMul * (1.0 / 255.0);
2479 alpha = (SplashCoord)alphaAcc * alphaMul;
2480
2481 if (alpha > 0) {
2482 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2483
2484 // set pixel
2485 pipe.shape = alpha;
2486 if (vectorAntialias && clipRes != splashClipAllInside) {
2487 drawAAPixel(&pipe, tx + x2, ty + y2);
2488 } else {
2489 drawPixel(&pipe, tx + x2, ty + y2,
2490 clipRes2 == splashClipAllInside);
2491 }
2492 }
2493
2494 // x scale Bresenham
2495 xSrc += xStep;
2496
2497 // x shear
2498 x1 += xSign;
2499
2500 // y shear
2501 y1 += yShear1;
2502 }
2503 break;
2504
2505 case splashModeRGB8:
2506 case splashModeBGR8:
2507 for (x = 0; x < scaledWidth; ++x) {
2508
2509 // x scale Bresenham
2510 xStep = xp;
2511 xt += xq;
2512 if (xt >= scaledWidth) {
2513 xt -= scaledWidth;
2514 ++xStep;
2515 }
2516
2517 // rotation
2518 if (rot) {
2519 x2 = (int)y1;
2520 y2 = -x1;
2521 } else {
2522 x2 = x1;
2523 y2 = (int)y1;
2524 }
2525
2526 // compute the filtered pixel at (x,y) after the x and y scaling
2527 // operations
2528 m = xStep > 0 ? xStep : 1;
2529 alphaAcc = 0;
2530 p = colorBuf + xSrc * 3;
2531 q = alphaBuf + xSrc;
2532 pixAcc0 = pixAcc1 = pixAcc2 = 0;
2533 for (i = 0; i < n; ++i) {
2534 for (j = 0; j < m; ++j) {
2535 pixAcc0 += *p++;
2536 pixAcc1 += *p++;
2537 pixAcc2 += *p++;
2538 alphaAcc += *q++;
2539 }
2540 p += 3 * (w - m);
2541 q += w - m;
2542 }
2543 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2544 alphaMul = pixMul * (1.0 / 255.0);
2545 alpha = (SplashCoord)alphaAcc * alphaMul;
2546
2547 if (alpha > 0) {
2548 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2549 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2550 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2551
2552 // set pixel
2553 pipe.shape = alpha;
2554 if (vectorAntialias && clipRes != splashClipAllInside) {
2555 drawAAPixel(&pipe, tx + x2, ty + y2);
2556 } else {
2557 drawPixel(&pipe, tx + x2, ty + y2,
2558 clipRes2 == splashClipAllInside);
2559 }
2560 }
2561
2562 // x scale Bresenham
2563 xSrc += xStep;
2564
2565 // x shear
2566 x1 += xSign;
2567
2568 // y shear
2569 y1 += yShear1;
2570 }
2571 break;
2572
2573 case splashModeXBGR8:
2574 for (x = 0; x < scaledWidth; ++x) {
2575 // x scale Bresenham
2576 xStep = xp;
2577 xt += xq;
2578 if (xt >= scaledWidth) {
2579 xt -= scaledWidth;
2580 ++xStep;
2581 }
2582
2583 // rotation
2584 if (rot) {
2585 x2 = (int)y1;
2586 y2 = -x1;
2587 } else {
2588 x2 = x1;
2589 y2 = (int)y1;
2590 }
2591
2592 // compute the filtered pixel at (x,y) after the x and y scaling
2593 // operations
2594 m = xStep > 0 ? xStep : 1;
2595 alphaAcc = 0;
2596 p = colorBuf + xSrc * 4;
2597 q = alphaBuf + xSrc;
2598 pixAcc0 = pixAcc1 = pixAcc2 = 0;
2599 for (i = 0; i < n; ++i) {
2600 for (j = 0; j < m; ++j) {
2601 pixAcc0 += *p++;
2602 pixAcc1 += *p++;
2603 pixAcc2 += *p++;
2604 p++;
2605 alphaAcc += *q++;
2606 }
2607 p += 4 * (w - m);
2608 q += w - m;
2609 }
2610 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2611 alphaMul = pixMul * (1.0 / 255.0);
2612 alpha = (SplashCoord)alphaAcc * alphaMul;
2613
2614 if (alpha > 0) {
2615 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2616 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2617 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2618 pix[3] = 255;
2619
2620 // set pixel
2621 pipe.shape = alpha;
2622 if (vectorAntialias && clipRes != splashClipAllInside) {
2623 drawAAPixel(&pipe, tx + x2, ty + y2);
2624 } else {
2625 drawPixel(&pipe, tx + x2, ty + y2,
2626 clipRes2 == splashClipAllInside);
2627 }
2628 }
2629
2630 // x scale Bresenham
2631 xSrc += xStep;
2632
2633 // x shear
2634 x1 += xSign;
2635
2636 // y shear
2637 y1 += yShear1;
2638 }
2639 break;
2640
2641
2642 #if SPLASH_CMYK
2643 case splashModeCMYK8:
2644 for (x = 0; x < scaledWidth; ++x) {
2645
2646 // x scale Bresenham
2647 xStep = xp;
2648 xt += xq;
2649 if (xt >= scaledWidth) {
2650 xt -= scaledWidth;
2651 ++xStep;
2652 }
2653
2654 // rotation
2655 if (rot) {
2656 x2 = (int)y1;
2657 y2 = -x1;
2658 } else {
2659 x2 = x1;
2660 y2 = (int)y1;
2661 }
2662
2663 // compute the filtered pixel at (x,y) after the x and y scaling
2664 // operations
2665 m = xStep > 0 ? xStep : 1;
2666 alphaAcc = 0;
2667 p = colorBuf + xSrc * 4;
2668 q = alphaBuf + xSrc;
2669 pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
2670 for (i = 0; i < n; ++i) {
2671 for (j = 0; j < m; ++j) {
2672 pixAcc0 += *p++;
2673 pixAcc1 += *p++;
2674 pixAcc2 += *p++;
2675 pixAcc3 += *p++;
2676 alphaAcc += *q++;
2677 }
2678 p += 4 * (w - m);
2679 q += w - m;
2680 }
2681 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2682 alphaMul = pixMul * (1.0 / 255.0);
2683 alpha = (SplashCoord)alphaAcc * alphaMul;
2684
2685 if (alpha > 0) {
2686 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2687 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2688 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2689 pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
2690
2691 // set pixel
2692 pipe.shape = alpha;
2693 if (vectorAntialias && clipRes != splashClipAllInside) {
2694 drawAAPixel(&pipe, tx + x2, ty + y2);
2695 } else {
2696 drawPixel(&pipe, tx + x2, ty + y2,
2697 clipRes2 == splashClipAllInside);
2698 }
2699 }
2700
2701 // x scale Bresenham
2702 xSrc += xStep;
2703
2704 // x shear
2705 x1 += xSign;
2706
2707 // y shear
2708 y1 += yShear1;
2709 }
2710 break;
2711 #endif // SPLASH_CMYK
2712 }
2713 }
2714
2715 } else {
2716
2717 // init y scale Bresenham
2718 yt = 0;
2719 lastYStep = 1;
2720
2721 for (y = 0; y < scaledHeight; ++y) {
2722
2723 // y scale Bresenham
2724 yStep = yp;
2725 yt += yq;
2726 if (yt >= scaledHeight) {
2727 yt -= scaledHeight;
2728 ++yStep;
2729 }
2730
2731 // read row(s) from image
2732 n = (yp > 0) ? yStep : lastYStep;
2733 if (n > 0) {
2734 p = colorBuf;
2735 for (i = 0; i < n; ++i) {
2736 (*src)(srcData, p, NULL);
2737 p += w * nComps;
2738 }
2739 }
2740 lastYStep = yStep;
2741
2742 // loop-invariant constants
2743 k1 = splashRound(xShear * ySign * y);
2744
2745 // clipping test
2746 if (clipRes != splashClipAllInside &&
2747 !rot &&
2748 (int)(yShear * k1) ==
2749 (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2750 if (xSign > 0) {
2751 spanXMin = tx + k1;
2752 spanXMax = spanXMin + (scaledWidth - 1);
2753 } else {
2754 spanXMax = tx + k1;
2755 spanXMin = spanXMax - (scaledWidth - 1);
2756 }
2757 spanY = ty + ySign * y + (int)(yShear * k1);
2758 clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2759 if (clipRes2 == splashClipAllOutside) {
2760 continue;
2761 }
2762 } else {
2763 clipRes2 = clipRes;
2764 }
2765
2766 // init x scale Bresenham
2767 xt = 0;
2768 xSrc = 0;
2769
2770 // x shear
2771 x1 = k1;
2772
2773 // y shear
2774 y1 = (SplashCoord)ySign * y + yShear * x1;
2775 // this is a kludge: if yShear1 is negative, then (int)y1 would
2776 // change immediately after the first pixel, which is not what
2777 // we want
2778 if (yShear1 < 0) {
2779 y1 += 0.999;
2780 }
2781
2782 // loop-invariant constants
2783 n = yStep > 0 ? yStep : 1;
2784
2785 switch (srcMode) {
2786
2787 case splashModeMono1:
2788 case splashModeMono8:
2789 for (x = 0; x < scaledWidth; ++x) {
2790
2791 // x scale Bresenham
2792 xStep = xp;
2793 xt += xq;
2794 if (xt >= scaledWidth) {
2795 xt -= scaledWidth;
2796 ++xStep;
2797 }
2798
2799 // rotation
2800 if (rot) {
2801 x2 = (int)y1;
2802 y2 = -x1;
2803 } else {
2804 x2 = x1;
2805 y2 = (int)y1;
2806 }
2807
2808 // compute the filtered pixel at (x,y) after the x and y scaling
2809 // operations
2810 m = xStep > 0 ? xStep : 1;
2811 p = colorBuf + xSrc;
2812 pixAcc0 = 0;
2813 for (i = 0; i < n; ++i) {
2814 for (j = 0; j < m; ++j) {
2815 pixAcc0 += *p++;
2816 }
2817 p += w - m;
2818 }
2819 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2820
2821 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2822
2823 // set pixel
2824 if (vectorAntialias && clipRes != splashClipAllInside) {
2825 pipe.shape = (SplashCoord)1;
2826 drawAAPixel(&pipe, tx + x2, ty + y2);
2827 } else {
2828 drawPixel(&pipe, tx + x2, ty + y2,
2829 clipRes2 == splashClipAllInside);
2830 }
2831
2832 // x scale Bresenham
2833 xSrc += xStep;
2834
2835 // x shear
2836 x1 += xSign;
2837
2838 // y shear
2839 y1 += yShear1;
2840 }
2841 break;
2842
2843 case splashModeRGB8:
2844 case splashModeBGR8:
2845 for (x = 0; x < scaledWidth; ++x) {
2846
2847 // x scale Bresenham
2848 xStep = xp;
2849 xt += xq;
2850 if (xt >= scaledWidth) {
2851 xt -= scaledWidth;
2852 ++xStep;
2853 }
2854
2855 // rotation
2856 if (rot) {
2857 x2 = (int)y1;
2858 y2 = -x1;
2859 } else {
2860 x2 = x1;
2861 y2 = (int)y1;
2862 }
2863
2864 // compute the filtered pixel at (x,y) after the x and y scaling
2865 // operations
2866 m = xStep > 0 ? xStep : 1;
2867 p = colorBuf + xSrc * 3;
2868 pixAcc0 = pixAcc1 = pixAcc2 = 0;
2869 for (i = 0; i < n; ++i) {
2870 for (j = 0; j < m; ++j) {
2871 pixAcc0 += *p++;
2872 pixAcc1 += *p++;
2873 pixAcc2 += *p++;
2874 }
2875 p += 3 * (w - m);
2876 }
2877 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2878
2879 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2880 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2881 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2882
2883 // set pixel
2884 if (vectorAntialias && clipRes != splashClipAllInside) {
2885 pipe.shape = (SplashCoord)1;
2886 drawAAPixel(&pipe, tx + x2, ty + y2);
2887 } else {
2888 drawPixel(&pipe, tx + x2, ty + y2,
2889 clipRes2 == splashClipAllInside);
2890 }
2891
2892 // x scale Bresenham
2893 xSrc += xStep;
2894
2895 // x shear
2896 x1 += xSign;
2897
2898 // y shear
2899 y1 += yShear1;
2900 }
2901 break;
2902
2903 case splashModeXBGR8:
2904 for (x = 0; x < scaledWidth; ++x) {
2905
2906 // x scale Bresenham
2907 xStep = xp;
2908 xt += xq;
2909 if (xt >= scaledWidth) {
2910 xt -= scaledWidth;
2911 ++xStep;
2912 }
2913
2914 // rotation
2915 if (rot) {
2916 x2 = (int)y1;
2917 y2 = -x1;
2918 } else {
2919 x2 = x1;
2920 y2 = (int)y1;
2921 }
2922
2923 // compute the filtered pixel at (x,y) after the x and y scaling
2924 // operations
2925 m = xStep > 0 ? xStep : 1;
2926 p = colorBuf + xSrc * 4;
2927 pixAcc0 = pixAcc1 = pixAcc2 = 0;
2928 for (i = 0; i < n; ++i) {
2929 for (j = 0; j < m; ++j) {
2930 pixAcc0 += *p++;
2931 pixAcc1 += *p++;
2932 pixAcc2 += *p++;
2933 p++;
2934 }
2935 p += 4 * (w - m);
2936 }
2937 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2938
2939 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2940 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2941 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2942 pix[3] = 255;
2943
2944 // set pixel
2945 if (vectorAntialias && clipRes != splashClipAllInside) {
2946 pipe.shape = (SplashCoord)1;
2947 drawAAPixel(&pipe, tx + x2, ty + y2);
2948 } else {
2949 drawPixel(&pipe, tx + x2, ty + y2,
2950 clipRes2 == splashClipAllInside);
2951 }
2952
2953 // x scale Bresenham
2954 xSrc += xStep;
2955
2956 // x shear
2957 x1 += xSign;
2958
2959 // y shear
2960 y1 += yShear1;
2961 }
2962 break;
2963
2964 #if SPLASH_CMYK
2965 case splashModeCMYK8:
2966 for (x = 0; x < scaledWidth; ++x) {
2967
2968 // x scale Bresenham
2969 xStep = xp;
2970 xt += xq;
2971 if (xt >= scaledWidth) {
2972 xt -= scaledWidth;
2973 ++xStep;
2974 }
2975
2976 // rotation
2977 if (rot) {
2978 x2 = (int)y1;
2979 y2 = -x1;
2980 } else {
2981 x2 = x1;
2982 y2 = (int)y1;
2983 }
2984
2985 // compute the filtered pixel at (x,y) after the x and y scaling
2986 // operations
2987 m = xStep > 0 ? xStep : 1;
2988 p = colorBuf + xSrc * 4;
2989 pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
2990 for (i = 0; i < n; ++i) {
2991 for (j = 0; j < m; ++j) {
2992 pixAcc0 += *p++;
2993 pixAcc1 += *p++;
2994 pixAcc2 += *p++;
2995 pixAcc3 += *p++;
2996 }
2997 p += 4 * (w - m);
2998 }
2999 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
3000
3001 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
3002 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
3003 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
3004 pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
3005
3006 // set pixel
3007 if (vectorAntialias && clipRes != splashClipAllInside) {
3008 pipe.shape = (SplashCoord)1;
3009 drawAAPixel(&pipe, tx + x2, ty + y2);
3010 } else {
3011 drawPixel(&pipe, tx + x2, ty + y2,
3012 clipRes2 == splashClipAllInside);
3013 }
3014
3015 // x scale Bresenham
3016 xSrc += xStep;
3017
3018 // x shear
3019 x1 += xSign;
3020
3021 // y shear
3022 y1 += yShear1;
3023 }
3024 break;
3025 #endif // SPLASH_CMYK
3026 }
3027 }
3028
3029 }
3030
3031 gfree(colorBuf);
3032 gfree(alphaBuf);
3033
3034 return splashOk;
3035 }
3036
composite(SplashBitmap * src,int xSrc,int ySrc,int xDest,int yDest,int w,int h,GBool noClip,GBool nonIsolated)3037 SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
3038 int xDest, int yDest, int w, int h,
3039 GBool noClip, GBool nonIsolated) {
3040 SplashPipe pipe;
3041 SplashColor pixel;
3042 Guchar alpha;
3043 Guchar *ap;
3044 int x, y;
3045
3046 if (src->mode != bitmap->mode) {
3047 return splashErrModeMismatch;
3048 }
3049
3050 if (src->alpha) {
3051 pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
3052 gTrue, nonIsolated);
3053 for (y = 0; y < h; ++y) {
3054 pipeSetXY(&pipe, xDest, yDest + y);
3055 ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
3056 for (x = 0; x < w; ++x) {
3057 alpha = *ap++;
3058 if (noClip || state->clip->test(xDest + x, yDest + y)) {
3059 // this uses shape instead of alpha, which isn't technically
3060 // correct, but works out the same
3061 src->getPixel(xSrc + x, ySrc + y, pixel);
3062 pipe.shape = (SplashCoord)(alpha / 255.0);
3063 pipeRun(&pipe);
3064 updateModX(xDest + x);
3065 updateModY(yDest + y);
3066 } else {
3067 pipeIncX(&pipe);
3068 }
3069 }
3070 }
3071 } else {
3072 pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
3073 gFalse, nonIsolated);
3074 for (y = 0; y < h; ++y) {
3075 pipeSetXY(&pipe, xDest, yDest + y);
3076 for (x = 0; x < w; ++x) {
3077 if (noClip || state->clip->test(xDest + x, yDest + y)) {
3078 src->getPixel(xSrc + x, ySrc + y, pixel);
3079 pipeRun(&pipe);
3080 updateModX(xDest + x);
3081 updateModY(yDest + y);
3082 } else {
3083 pipeIncX(&pipe);
3084 }
3085 }
3086 }
3087 }
3088
3089 return splashOk;
3090 }
3091
compositeBackground(SplashColorPtr color)3092 void Splash::compositeBackground(SplashColorPtr color) {
3093 SplashColorPtr p;
3094 Guchar *q;
3095 Guchar alpha, alpha1, c, color0, color1, color2;
3096 #if SPLASH_CMYK
3097 Guchar color3;
3098 #endif
3099 int x, y, mask;
3100
3101 if (unlikely(bitmap->alpha == NULL)) {
3102 error(-1, "bitmap->alpha is NULL in Splash::compositeBackground");
3103 return;
3104 }
3105
3106 switch (bitmap->mode) {
3107 case splashModeMono1:
3108 color0 = color[0];
3109 for (y = 0; y < bitmap->height; ++y) {
3110 p = &bitmap->data[y * bitmap->rowSize];
3111 q = &bitmap->alpha[y * bitmap->width];
3112 mask = 0x80;
3113 for (x = 0; x < bitmap->width; ++x) {
3114 alpha = *q++;
3115 alpha1 = 255 - alpha;
3116 c = (*p & mask) ? 0xff : 0x00;
3117 c = div255(alpha1 * color0 + alpha * c);
3118 if (c & 0x80) {
3119 *p |= mask;
3120 } else {
3121 *p &= ~mask;
3122 }
3123 if (!(mask >>= 1)) {
3124 mask = 0x80;
3125 ++p;
3126 }
3127 }
3128 }
3129 break;
3130 case splashModeMono8:
3131 color0 = color[0];
3132 for (y = 0; y < bitmap->height; ++y) {
3133 p = &bitmap->data[y * bitmap->rowSize];
3134 q = &bitmap->alpha[y * bitmap->width];
3135 for (x = 0; x < bitmap->width; ++x) {
3136 alpha = *q++;
3137 alpha1 = 255 - alpha;
3138 p[0] = div255(alpha1 * color0 + alpha * p[0]);
3139 ++p;
3140 }
3141 }
3142 break;
3143 case splashModeRGB8:
3144 case splashModeBGR8:
3145 color0 = color[0];
3146 color1 = color[1];
3147 color2 = color[2];
3148 for (y = 0; y < bitmap->height; ++y) {
3149 p = &bitmap->data[y * bitmap->rowSize];
3150 q = &bitmap->alpha[y * bitmap->width];
3151 for (x = 0; x < bitmap->width; ++x) {
3152 alpha = *q++;
3153 if (alpha == 0)
3154 {
3155 p[0] = color0;
3156 p[1] = color1;
3157 p[2] = color2;
3158 }
3159 else if (alpha != 255)
3160 {
3161 alpha1 = 255 - alpha;
3162 p[0] = div255(alpha1 * color0 + alpha * p[0]);
3163 p[1] = div255(alpha1 * color1 + alpha * p[1]);
3164 p[2] = div255(alpha1 * color2 + alpha * p[2]);
3165 }
3166 p += 3;
3167 }
3168 }
3169 break;
3170 case splashModeXBGR8:
3171 color0 = color[0];
3172 color1 = color[1];
3173 color2 = color[2];
3174 for (y = 0; y < bitmap->height; ++y) {
3175 p = &bitmap->data[y * bitmap->rowSize];
3176 q = &bitmap->alpha[y * bitmap->width];
3177 for (x = 0; x < bitmap->width; ++x) {
3178 alpha = *q++;
3179 if (alpha == 0)
3180 {
3181 p[0] = color0;
3182 p[1] = color1;
3183 p[2] = color2;
3184 }
3185 else if (alpha != 255)
3186 {
3187 alpha1 = 255 - alpha;
3188 p[0] = div255(alpha1 * color0 + alpha * p[0]);
3189 p[1] = div255(alpha1 * color1 + alpha * p[1]);
3190 p[2] = div255(alpha1 * color2 + alpha * p[2]);
3191 }
3192 p[3] = 255;
3193 p += 4;
3194 }
3195 }
3196 break;
3197 #if SPLASH_CMYK
3198 case splashModeCMYK8:
3199 color0 = color[0];
3200 color1 = color[1];
3201 color2 = color[2];
3202 color3 = color[3];
3203 for (y = 0; y < bitmap->height; ++y) {
3204 p = &bitmap->data[y * bitmap->rowSize];
3205 q = &bitmap->alpha[y * bitmap->width];
3206 for (x = 0; x < bitmap->width; ++x) {
3207 alpha = *q++;
3208 alpha1 = 255 - alpha;
3209 p[0] = div255(alpha1 * color0 + alpha * p[0]);
3210 p[1] = div255(alpha1 * color1 + alpha * p[1]);
3211 p[2] = div255(alpha1 * color2 + alpha * p[2]);
3212 p[3] = div255(alpha1 * color3 + alpha * p[3]);
3213 p += 4;
3214 }
3215 }
3216 break;
3217 #endif
3218 }
3219 memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
3220 }
3221
gouraudTriangleShadedFill(SplashGouraudColor * shading)3222 GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
3223 {
3224 double xdbl[3] = {0., 0., 0.};
3225 double ydbl[3] = {0., 0., 0.};
3226 int x[3] = {0, 0, 0};
3227 int y[3] = {0, 0, 0};
3228 double xt=0., xa=0., yt=0.;
3229 double ca=0., ct=0.;
3230
3231 // triangle interpolation:
3232 //
3233 double scanLimitMapL[2] = {0., 0.};
3234 double scanLimitMapR[2] = {0., 0.};
3235 double scanColorMapL[2] = {0., 0.};
3236 double scanColorMapR[2] = {0., 0.};
3237 double scanColorMap[2] = {0., 0.};
3238 int scanEdgeL[2] = { 0, 0 };
3239 int scanEdgeR[2] = { 0, 0 };
3240 GBool hasFurtherSegment = gFalse;
3241
3242 int scanLineOff = 0;
3243 int bitmapOff = 0;
3244 int scanLimitR = 0, scanLimitL = 0, Yt = 0;
3245
3246 int bitmapWidth = bitmap->getWidth();
3247 SplashClip* clip = getClip();
3248 SplashBitmap *blitTarget = bitmap;
3249 SplashColorPtr bitmapData = bitmap->getDataPtr();
3250 SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
3251 SplashColorPtr cur = NULL;
3252 SplashCoord* userToCanvasMatrix = getMatrix();
3253 SplashColorMode bitmapMode = bitmap->getMode();
3254 GBool hasAlpha = (bitmapAlpha != NULL);
3255 int rowSize = bitmap->getRowSize();
3256 int colorComps = 0;
3257 switch (bitmapMode) {
3258 case splashModeMono1:
3259 break;
3260 case splashModeMono8:
3261 colorComps=1;
3262 break;
3263 case splashModeRGB8:
3264 colorComps=3;
3265 break;
3266 case splashModeBGR8:
3267 colorComps=3;
3268 break;
3269 case splashModeXBGR8:
3270 colorComps=4;
3271 break;
3272 #if SPLASH_CMYK
3273 case splashModeCMYK8:
3274 colorComps=4;
3275 break;
3276 #endif
3277 }
3278
3279 SplashPipe pipe;
3280 SplashColor cSrcVal;
3281
3282 pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse, gFalse);
3283
3284 if (vectorAntialias) {
3285 if (aaBuf == NULL)
3286 return gFalse; // fall back to old behaviour
3287 drawAAPixelInit();
3288 }
3289
3290 // idea:
3291 // 1. If pipe->noTransparency && !state->blendFunc
3292 // -> blit directly into the drawing surface!
3293 // -> disable alpha manually.
3294 // 2. Otherwise:
3295 // - blit also directly, but into an intermediate surface.
3296 // Afterwards, blit the intermediate surface using the drawing pipeline.
3297 // This is necessary because triangle elements can be on top of each
3298 // other, so the complete shading needs to be drawn before opacity is
3299 // applied.
3300 // - the final step, is performed using a SplashPipe:
3301 // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
3302 // - invoke drawPixel(&pipe,X,Y,bNoClip);
3303 GBool bDirectBlit = vectorAntialias ? gFalse : pipe.noTransparency && !state->blendFunc;
3304 if (!bDirectBlit) {
3305 blitTarget = new SplashBitmap(bitmap->getWidth(),
3306 bitmap->getHeight(),
3307 bitmap->getRowPad(),
3308 bitmap->getMode(),
3309 gTrue,
3310 bitmap->getRowSize() >= 0);
3311 bitmapData = blitTarget->getDataPtr();
3312 bitmapAlpha = blitTarget->getAlphaPtr();
3313
3314 // initialisation seems to be necessary:
3315 int S = bitmap->getWidth() * bitmap->getHeight();
3316 for (int i = 0; i < S; ++i)
3317 bitmapAlpha[i] = 0;
3318 hasAlpha = gTrue;
3319 }
3320
3321 if (shading->isParameterized()) {
3322 double color[3];
3323 double colorinterp;
3324
3325 for (int i = 0; i < shading->getNTriangles(); ++i) {
3326 shading->getTriangle(i,
3327 xdbl + 0, ydbl + 0, color + 0,
3328 xdbl + 1, ydbl + 1, color + 1,
3329 xdbl + 2, ydbl + 2, color + 2);
3330 for (int m = 0; m < 3; ++m) {
3331 xt = xdbl[m] * userToCanvasMatrix[0] + ydbl[m] * userToCanvasMatrix[2] + userToCanvasMatrix[4];
3332 yt = xdbl[m] * userToCanvasMatrix[1] + ydbl[m] * userToCanvasMatrix[3] + userToCanvasMatrix[5];
3333 xdbl[m] = xt;
3334 ydbl[m] = yt;
3335 // we operate on scanlines which are integer offsets into the
3336 // raster image. The double offsets are of no use here.
3337 x[m] = splashRound(xt);
3338 y[m] = splashRound(yt);
3339 }
3340 // sort according to y coordinate to simplify sweep through scanlines:
3341 // INSERTION SORT.
3342 if (y[0] > y[1]) {
3343 Guswap(x[0], x[1]);
3344 Guswap(y[0], y[1]);
3345 Guswap(color[0], color[1]);
3346 }
3347 // first two are sorted.
3348 assert(y[0] <= y[1]);
3349 if (y[1] > y[2]) {
3350 int tmpX = x[2];
3351 int tmpY = y[2];
3352 double tmpC = color[2];
3353 x[2] = x[1]; y[2] = y[1]; color[2] = color[1];
3354
3355 if (y[0] > tmpY) {
3356 x[1] = x[0]; y[1] = y[0]; color[1] = color[0];
3357 x[0] = tmpX; y[0] = tmpY; color[0] = tmpC;
3358 } else {
3359 x[1] = tmpX; y[1] = tmpY; color[1] = tmpC;
3360 }
3361 }
3362 // first three are sorted
3363 assert(y[0] <= y[1]);
3364 assert(y[1] <= y[2]);
3365 /////
3366
3367 // this here is det( T ) == 0
3368 // where T is the matrix to map to barycentric coordinates.
3369 if ((x[0] - x[2]) * (y[1] - y[2]) - (x[1] - x[2]) * (y[0] - y[2]) == 0)
3370 continue; // degenerate triangle.
3371
3372 // this here initialises the scanline generation.
3373 // We start with low Y coordinates and sweep up to the large Y
3374 // coordinates.
3375 //
3376 // scanEdgeL[m] in {0,1,2} m=0,1
3377 // scanEdgeR[m] in {0,1,2} m=0,1
3378 //
3379 // are the two edges between which scanlines are (currently)
3380 // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
3381 // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
3382 //
3383 scanEdgeL[0] = 0;
3384 scanEdgeR[0] = 0;
3385 if (y[0] == y[1]) {
3386 scanEdgeL[0] = 1;
3387 scanEdgeL[1] = scanEdgeR[1] = 2;
3388
3389 } else {
3390 scanEdgeL[1] = 1; scanEdgeR[1] = 2;
3391 }
3392 assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]);
3393 assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]);
3394
3395 // Ok. Now prepare the linear maps which map the y coordinate of
3396 // the current scanline to the corresponding LEFT and RIGHT x
3397 // coordinate (which define the scanline).
3398 scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3399 scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
3400 scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3401 scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
3402
3403 xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];
3404 xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];
3405 if (xa > xt) {
3406 // I have "left" is to the right of "right".
3407 // Exchange sides!
3408 Guswap(scanEdgeL[0], scanEdgeR[0]);
3409 Guswap(scanEdgeL[1], scanEdgeR[1]);
3410 Guswap(scanLimitMapL[0], scanLimitMapR[0]);
3411 Guswap(scanLimitMapL[1], scanLimitMapR[1]);
3412 // FIXME I'm sure there is a more efficient way to check this.
3413 }
3414
3415 // Same game: we can linearly interpolate the color based on the
3416 // current y coordinate (that's correct for triangle
3417 // interpolation due to linearity. We could also have done it in
3418 // barycentric coordinates, but that's slightly more involved)
3419 scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3420 scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
3421 scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3422 scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
3423
3424 Yt = y[2];
3425 hasFurtherSegment = (y[1] < y[2]);
3426 scanLineOff = y[0] * rowSize;
3427
3428 for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) {
3429 if (hasFurtherSegment && Y == y[1]) {
3430 // SWEEP EVENT: we encountered the next segment.
3431 //
3432 // switch to next segment, either at left end or at right
3433 // end:
3434 if (scanEdgeL[1] == 1) {
3435 scanEdgeL[0] = 1;
3436 scanEdgeL[1] = 2;
3437 scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3438 scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
3439
3440 scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3441 scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
3442 } else if (scanEdgeR[1] == 1) {
3443 scanEdgeR[0] = 1;
3444 scanEdgeR[1] = 2;
3445 scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3446 scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
3447
3448 scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3449 scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
3450 }
3451 assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
3452 assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
3453 hasFurtherSegment = gFalse;
3454 }
3455
3456 yt = Y;
3457
3458 xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
3459 xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
3460
3461 ca = yt * scanColorMapL[0] + scanColorMapL[1];
3462 ct = yt * scanColorMapR[0] + scanColorMapR[1];
3463
3464 scanLimitL = splashRound(xa);
3465 scanLimitR = splashRound(xt);
3466
3467 // Ok. Now: init the color interpolation depending on the X
3468 // coordinate inside of the current scanline:
3469 scanColorMap[0] = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));
3470 scanColorMap[1] = ca - scanLimitL * scanColorMap[0];
3471
3472 // handled by clipping:
3473 // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
3474 assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
3475 assert(scanLineOff == Y * rowSize);
3476
3477 colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];
3478
3479 bitmapOff = scanLineOff + scanLimitL * colorComps;
3480 for (int X = scanLimitL; X <= scanLimitR; ++X, colorinterp += scanColorMap[0], bitmapOff += colorComps) {
3481 // FIXME : standard rectangular clipping can be done for a
3482 // complete scanline which is faster
3483 // --> see SplashClip and its methods
3484 if (!clip->test(X, Y))
3485 continue;
3486
3487 assert(fabs(colorinterp - (scanColorMap[0] * X + scanColorMap[1])) < 1e-10);
3488 assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);
3489
3490 shading->getParameterizedColor(colorinterp, bitmapMode, &bitmapData[bitmapOff]);
3491
3492 // make the shading visible.
3493 // Note that opacity is handled by the bDirectBlit stuff, see
3494 // above for comments and below for implementation.
3495 if (hasAlpha)
3496 bitmapAlpha[Y * bitmapWidth + X] = 255;
3497 }
3498 }
3499 }
3500 } else {
3501 return gFalse;
3502 }
3503
3504 if (!bDirectBlit) {
3505 // ok. Finalize the stuff by blitting the shading into the final
3506 // geometry, this time respecting the rendering pipe.
3507 int W = blitTarget->getWidth();
3508 int H = blitTarget->getHeight();
3509 cur = cSrcVal;
3510
3511 for (int X = 0; X < W; ++X) {
3512 for (int Y = 0; Y < H; ++Y) {
3513 if (!bitmapAlpha[Y * bitmapWidth + X])
3514 continue; // draw only parts of the shading!
3515 bitmapOff = Y * rowSize + colorComps * X;
3516
3517 for (int m = 0; m < colorComps; ++m)
3518 cur[m] = bitmapData[bitmapOff + m];
3519 if (vectorAntialias) {
3520 drawAAPixel(&pipe, X, Y);
3521 } else {
3522 drawPixel(&pipe, X, Y, gTrue); // no clipping - has already been done.
3523 }
3524 }
3525 }
3526
3527 delete blitTarget;
3528 blitTarget = NULL;
3529 }
3530
3531 return gTrue;
3532 }
3533
blitTransparent(SplashBitmap * src,int xSrc,int ySrc,int xDest,int yDest,int w,int h)3534 SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
3535 int xDest, int yDest, int w, int h) {
3536 SplashColor pixel;
3537 SplashColorPtr p, sp;
3538 Guchar *q;
3539 int x, y, mask;
3540
3541 if (src->mode != bitmap->mode) {
3542 return splashErrModeMismatch;
3543 }
3544
3545 switch (bitmap->mode) {
3546 case splashModeMono1:
3547 for (y = 0; y < h; ++y) {
3548 p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
3549 mask = 0x80 >> (xDest & 7);
3550 for (x = 0; x < w; ++x) {
3551 src->getPixel(xSrc + x, ySrc + y, pixel);
3552 if (pixel[0]) {
3553 *p |= mask;
3554 } else {
3555 *p &= ~mask;
3556 }
3557 if (!(mask >>= 1)) {
3558 mask = 0x80;
3559 ++p;
3560 }
3561 }
3562 }
3563 break;
3564 case splashModeMono8:
3565 for (y = 0; y < h; ++y) {
3566 p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
3567 for (x = 0; x < w; ++x) {
3568 src->getPixel(xSrc + x, ySrc + y, pixel);
3569 *p++ = pixel[0];
3570 }
3571 }
3572 break;
3573 case splashModeRGB8:
3574 case splashModeBGR8:
3575 for (y = 0; y < h; ++y) {
3576 p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
3577 sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
3578 for (x = 0; x < w; ++x) {
3579 *p++ = *sp++;
3580 *p++ = *sp++;
3581 *p++ = *sp++;
3582 }
3583 }
3584 break;
3585 case splashModeXBGR8:
3586 for (y = 0; y < h; ++y) {
3587 p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
3588 sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
3589 for (x = 0; x < w; ++x) {
3590 *p++ = *sp++;
3591 *p++ = *sp++;
3592 *p++ = *sp++;
3593 *p++ = 255;
3594 sp++;
3595 }
3596 }
3597 break;
3598 #if SPLASH_CMYK
3599 case splashModeCMYK8:
3600 for (y = 0; y < h; ++y) {
3601 p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
3602 for (x = 0; x < w; ++x) {
3603 src->getPixel(xSrc + x, ySrc + y, pixel);
3604 *p++ = pixel[0];
3605 *p++ = pixel[1];
3606 *p++ = pixel[2];
3607 *p++ = pixel[3];
3608 }
3609 }
3610 break;
3611 #endif
3612 }
3613
3614 if (bitmap->alpha) {
3615 for (y = 0; y < h; ++y) {
3616 q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
3617 memset(q, 0x00, w);
3618 }
3619 }
3620
3621 return splashOk;
3622 }
3623
makeStrokePath(SplashPath * path,GBool flatten)3624 SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
3625 SplashPath *pathIn, *pathOut;
3626 SplashCoord w, d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
3627 SplashCoord crossprod, dotprod, miter, m;
3628 GBool first, last, closed;
3629 int subpathStart, next, i;
3630 int left0, left1, left2, right0, right1, right2, join0, join1, join2;
3631 int leftFirst, rightFirst, firstPt;
3632
3633 if (flatten) {
3634 pathIn = flattenPath(path, state->matrix, state->flatness);
3635 if (state->lineDashLength > 0) {
3636 pathOut = makeDashedPath(pathIn);
3637 delete pathIn;
3638 pathIn = pathOut;
3639 }
3640 } else {
3641 pathIn = path;
3642 }
3643
3644 subpathStart = 0; // make gcc happy
3645 closed = gFalse; // make gcc happy
3646 left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
3647 leftFirst = rightFirst = firstPt = 0; // make gcc happy
3648
3649 pathOut = new SplashPath();
3650 w = state->lineWidth;
3651
3652 for (i = 0; i < pathIn->length - 1; ++i) {
3653 if (pathIn->flags[i] & splashPathLast) {
3654 continue;
3655 }
3656 if ((first = pathIn->flags[i] & splashPathFirst)) {
3657 subpathStart = i;
3658 closed = pathIn->flags[i] & splashPathClosed;
3659 }
3660 last = pathIn->flags[i+1] & splashPathLast;
3661
3662 // compute the deltas for segment (i, i+1)
3663 d = splashDist(pathIn->pts[i].x, pathIn->pts[i].y,
3664 pathIn->pts[i+1].x, pathIn->pts[i+1].y);
3665 if (d == 0) {
3666 // we need to draw end caps on zero-length lines
3667 //~ not clear what the behavior should be for splashLineCapButt
3668 //~ with d==0
3669 dx = 0;
3670 dy = 1;
3671 } else {
3672 d = (SplashCoord)1 / d;
3673 dx = d * (pathIn->pts[i+1].x - pathIn->pts[i].x);
3674 dy = d * (pathIn->pts[i+1].y - pathIn->pts[i].y);
3675 }
3676 wdx = (SplashCoord)0.5 * w * dx;
3677 wdy = (SplashCoord)0.5 * w * dy;
3678
3679 // compute the deltas for segment (i+1, next)
3680 next = last ? subpathStart + 1 : i + 2;
3681 d = splashDist(pathIn->pts[i+1].x, pathIn->pts[i+1].y,
3682 pathIn->pts[next].x, pathIn->pts[next].y);
3683 if (d == 0) {
3684 // we need to draw end caps on zero-length lines
3685 //~ not clear what the behavior should be for splashLineCapButt
3686 //~ with d==0
3687 dxNext = 0;
3688 dyNext = 1;
3689 } else {
3690 d = (SplashCoord)1 / d;
3691 dxNext = d * (pathIn->pts[next].x - pathIn->pts[i+1].x);
3692 dyNext = d * (pathIn->pts[next].y - pathIn->pts[i+1].y);
3693 }
3694 wdxNext = (SplashCoord)0.5 * w * dxNext;
3695 wdyNext = (SplashCoord)0.5 * w * dyNext;
3696
3697 // draw the start cap
3698 pathOut->moveTo(pathIn->pts[i].x - wdy, pathIn->pts[i].y + wdx);
3699 if (i == subpathStart) {
3700 firstPt = pathOut->length - 1;
3701 }
3702 if (first && !closed) {
3703 switch (state->lineCap) {
3704 case splashLineCapButt:
3705 pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
3706 break;
3707 case splashLineCapRound:
3708 pathOut->curveTo(pathIn->pts[i].x - wdy - bezierCircle * wdx,
3709 pathIn->pts[i].y + wdx - bezierCircle * wdy,
3710 pathIn->pts[i].x - wdx - bezierCircle * wdy,
3711 pathIn->pts[i].y - wdy + bezierCircle * wdx,
3712 pathIn->pts[i].x - wdx,
3713 pathIn->pts[i].y - wdy);
3714 pathOut->curveTo(pathIn->pts[i].x - wdx + bezierCircle * wdy,
3715 pathIn->pts[i].y - wdy - bezierCircle * wdx,
3716 pathIn->pts[i].x + wdy - bezierCircle * wdx,
3717 pathIn->pts[i].y - wdx - bezierCircle * wdy,
3718 pathIn->pts[i].x + wdy,
3719 pathIn->pts[i].y - wdx);
3720 break;
3721 case splashLineCapProjecting:
3722 pathOut->lineTo(pathIn->pts[i].x - wdx - wdy,
3723 pathIn->pts[i].y + wdx - wdy);
3724 pathOut->lineTo(pathIn->pts[i].x - wdx + wdy,
3725 pathIn->pts[i].y - wdx - wdy);
3726 pathOut->lineTo(pathIn->pts[i].x + wdy,
3727 pathIn->pts[i].y - wdx);
3728 break;
3729 }
3730 } else {
3731 pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
3732 }
3733
3734 // draw the left side of the segment rectangle
3735 left2 = pathOut->length - 1;
3736 pathOut->lineTo(pathIn->pts[i+1].x + wdy, pathIn->pts[i+1].y - wdx);
3737
3738 // draw the end cap
3739 if (last && !closed) {
3740 switch (state->lineCap) {
3741 case splashLineCapButt:
3742 pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
3743 break;
3744 case splashLineCapRound:
3745 pathOut->curveTo(pathIn->pts[i+1].x + wdy + bezierCircle * wdx,
3746 pathIn->pts[i+1].y - wdx + bezierCircle * wdy,
3747 pathIn->pts[i+1].x + wdx + bezierCircle * wdy,
3748 pathIn->pts[i+1].y + wdy - bezierCircle * wdx,
3749 pathIn->pts[i+1].x + wdx,
3750 pathIn->pts[i+1].y + wdy);
3751 pathOut->curveTo(pathIn->pts[i+1].x + wdx - bezierCircle * wdy,
3752 pathIn->pts[i+1].y + wdy + bezierCircle * wdx,
3753 pathIn->pts[i+1].x - wdy + bezierCircle * wdx,
3754 pathIn->pts[i+1].y + wdx + bezierCircle * wdy,
3755 pathIn->pts[i+1].x - wdy,
3756 pathIn->pts[i+1].y + wdx);
3757 break;
3758 case splashLineCapProjecting:
3759 pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx,
3760 pathIn->pts[i+1].y - wdx + wdy);
3761 pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx,
3762 pathIn->pts[i+1].y + wdx + wdy);
3763 pathOut->lineTo(pathIn->pts[i+1].x - wdy,
3764 pathIn->pts[i+1].y + wdx);
3765 break;
3766 }
3767 } else {
3768 pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
3769 }
3770
3771 // draw the right side of the segment rectangle
3772 right2 = pathOut->length - 1;
3773 pathOut->close();
3774
3775 // draw the join
3776 join2 = pathOut->length;
3777 if (!last || closed) {
3778 crossprod = dx * dyNext - dy * dxNext;
3779 dotprod = -(dx * dxNext + dy * dyNext);
3780 if (dotprod > 0.99999) {
3781 // avoid a divide-by-zero -- set miter to something arbitrary
3782 // such that sqrt(miter) will exceed miterLimit (and m is never
3783 // used in that situation)
3784 miter = (state->miterLimit + 1) * (state->miterLimit + 1);
3785 m = 0;
3786 } else {
3787 miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
3788 if (miter < 1) {
3789 // this can happen because of floating point inaccuracies
3790 miter = 1;
3791 }
3792 m = splashSqrt(miter - 1);
3793 }
3794
3795 // round join
3796 if (state->lineJoin == splashLineJoinRound) {
3797 pathOut->moveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3798 pathIn->pts[i+1].y);
3799 pathOut->curveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3800 pathIn->pts[i+1].y + bezierCircle2 * w,
3801 pathIn->pts[i+1].x + bezierCircle2 * w,
3802 pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
3803 pathIn->pts[i+1].x,
3804 pathIn->pts[i+1].y + (SplashCoord)0.5 * w);
3805 pathOut->curveTo(pathIn->pts[i+1].x - bezierCircle2 * w,
3806 pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
3807 pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
3808 pathIn->pts[i+1].y + bezierCircle2 * w,
3809 pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
3810 pathIn->pts[i+1].y);
3811 pathOut->curveTo(pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
3812 pathIn->pts[i+1].y - bezierCircle2 * w,
3813 pathIn->pts[i+1].x - bezierCircle2 * w,
3814 pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
3815 pathIn->pts[i+1].x,
3816 pathIn->pts[i+1].y - (SplashCoord)0.5 * w);
3817 pathOut->curveTo(pathIn->pts[i+1].x + bezierCircle2 * w,
3818 pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
3819 pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3820 pathIn->pts[i+1].y - bezierCircle2 * w,
3821 pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3822 pathIn->pts[i+1].y);
3823
3824 } else {
3825 pathOut->moveTo(pathIn->pts[i+1].x, pathIn->pts[i+1].y);
3826
3827 // angle < 180
3828 if (crossprod < 0) {
3829 pathOut->lineTo(pathIn->pts[i+1].x - wdyNext,
3830 pathIn->pts[i+1].y + wdxNext);
3831 // miter join inside limit
3832 if (state->lineJoin == splashLineJoinMiter &&
3833 splashSqrt(miter) <= state->miterLimit) {
3834 pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx * m,
3835 pathIn->pts[i+1].y + wdx + wdy * m);
3836 pathOut->lineTo(pathIn->pts[i+1].x - wdy,
3837 pathIn->pts[i+1].y + wdx);
3838 // bevel join or miter join outside limit
3839 } else {
3840 pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
3841 }
3842
3843 // angle >= 180
3844 } else {
3845 pathOut->lineTo(pathIn->pts[i+1].x + wdy,
3846 pathIn->pts[i+1].y - wdx);
3847 // miter join inside limit
3848 if (state->lineJoin == splashLineJoinMiter &&
3849 splashSqrt(miter) <= state->miterLimit) {
3850 pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx * m,
3851 pathIn->pts[i+1].y - wdx + wdy * m);
3852 pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
3853 pathIn->pts[i+1].y - wdxNext);
3854 // bevel join or miter join outside limit
3855 } else {
3856 pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
3857 pathIn->pts[i+1].y - wdxNext);
3858 }
3859 }
3860 }
3861
3862 pathOut->close();
3863 }
3864
3865 // add stroke adjustment hints
3866 if (state->strokeAdjust) {
3867 if (i >= subpathStart + 1) {
3868 if (i >= subpathStart + 2) {
3869 pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
3870 pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
3871 } else {
3872 pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2);
3873 }
3874 pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
3875 }
3876 left0 = left1;
3877 left1 = left2;
3878 right0 = right1;
3879 right1 = right2;
3880 join0 = join1;
3881 join1 = join2;
3882 if (i == subpathStart) {
3883 leftFirst = left2;
3884 rightFirst = right2;
3885 }
3886 if (last) {
3887 if (i >= subpathStart + 2) {
3888 pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
3889 pathOut->addStrokeAdjustHint(left1, right1,
3890 join0, pathOut->length - 1);
3891 } else {
3892 pathOut->addStrokeAdjustHint(left1, right1,
3893 firstPt, pathOut->length - 1);
3894 }
3895 if (closed) {
3896 pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst);
3897 pathOut->addStrokeAdjustHint(left1, right1,
3898 rightFirst + 1, rightFirst + 1);
3899 pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
3900 left1 + 1, right1);
3901 pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
3902 join1, pathOut->length - 1);
3903 }
3904 }
3905 }
3906 }
3907
3908 if (pathIn != path) {
3909 delete pathIn;
3910 }
3911
3912 return pathOut;
3913 }
3914
dumpPath(SplashPath * path)3915 void Splash::dumpPath(SplashPath *path) {
3916 int i;
3917
3918 for (i = 0; i < path->length; ++i) {
3919 printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
3920 i, (double)path->pts[i].x, (double)path->pts[i].y,
3921 (path->flags[i] & splashPathFirst) ? " first" : "",
3922 (path->flags[i] & splashPathLast) ? " last" : "",
3923 (path->flags[i] & splashPathClosed) ? " closed" : "",
3924 (path->flags[i] & splashPathCurve) ? " curve" : "");
3925 }
3926 }
3927
dumpXPath(SplashXPath * path)3928 void Splash::dumpXPath(SplashXPath *path) {
3929 int i;
3930
3931 for (i = 0; i < path->length; ++i) {
3932 printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
3933 i, (double)path->segs[i].x0, (double)path->segs[i].y0,
3934 (double)path->segs[i].x1, (double)path->segs[i].y1,
3935 (path->segs[i].flags & splashXPathFirst) ? "F" : " ",
3936 (path->segs[i].flags & splashXPathLast) ? "L" : " ",
3937 (path->segs[i].flags & splashXPathEnd0) ? "0" : " ",
3938 (path->segs[i].flags & splashXPathEnd1) ? "1" : " ",
3939 (path->segs[i].flags & splashXPathHoriz) ? "H" : " ",
3940 (path->segs[i].flags & splashXPathVert) ? "V" : " ",
3941 (path->segs[i].flags & splashXPathFlip) ? "P" : " ");
3942 }
3943 }
3944
shadedFill(SplashPath * path,GBool hasBBox,SplashPattern * pattern)3945 SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
3946 SplashPattern *pattern) {
3947 SplashPipe pipe;
3948 SplashXPath *xPath;
3949 SplashXPathScanner *scanner;
3950 int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
3951 SplashClipResult clipRes;
3952
3953 if (aaBuf == NULL) { // should not happen, but to be secure
3954 return splashErrGeneric;
3955 }
3956 if (path->length == 0) {
3957 return splashErrEmptyPath;
3958 }
3959 xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
3960 xPath->aaScale();
3961 xPath->sort();
3962 scanner = new SplashXPathScanner(xPath, gFalse);
3963
3964 // get the min and max x and y values
3965 scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
3966
3967 // check clipping
3968 if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) {
3969 // limit the y range
3970 if (yMinI < state->clip->getYMinI()) {
3971 yMinI = state->clip->getYMinI();
3972 }
3973 if (yMaxI > state->clip->getYMaxI()) {
3974 yMaxI = state->clip->getYMaxI();
3975 }
3976
3977 pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias && !hasBBox, gFalse);
3978
3979 // draw the spans
3980 for (y = yMinI; y <= yMaxI; ++y) {
3981 scanner->renderAALine(aaBuf, &x0, &x1, y);
3982 if (clipRes != splashClipAllInside) {
3983 state->clip->clipAALine(aaBuf, &x0, &x1, y);
3984 }
3985 drawAALine(&pipe, x0, x1, y);
3986 }
3987 }
3988 opClipRes = clipRes;
3989
3990 delete scanner;
3991 delete xPath;
3992 return splashOk;
3993 }
3994