1 //========================================================================
5 //========================================================================
10 #pragma implementation
16 #include "SplashErrorCodes.h"
17 #include "SplashMath.h"
18 #include "SplashBitmap.h"
19 #include "SplashState.h"
20 #include "SplashPath.h"
21 #include "SplashXPath.h"
22 #include "SplashXPathScanner.h"
23 #include "SplashPattern.h"
24 #include "SplashScreen.h"
25 #include "SplashFont.h"
26 #include "SplashGlyphBitmap.h"
29 //------------------------------------------------------------------------
31 // distance of Bezier control point from center for circle approximation
32 // = (4 * (sqrt(2) - 1) / 3) * r
33 #define bezierCircle ((SplashCoord)0.55228475)
34 #define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
36 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
37 static inline Guchar
div255(int x
) {
38 return (Guchar
)((x
+ (x
>> 8) + 0x80) >> 8);
41 //------------------------------------------------------------------------
43 //------------------------------------------------------------------------
45 #define splashPipeMaxStages 9
52 SplashPattern
*pattern
;
54 // source alpha and color
61 // non-isolated group alpha0
65 SplashColorPtr softMaskPtr
;
67 // destination alpha and color
68 SplashColorPtr destColorPtr
;
75 // result alpha and color
77 SplashPipeResultColorCtrl resultColorCtrl
;
79 // non-isolated group correction
83 SplashPipeResultColorCtrl
Splash::pipeResultColorNoAlphaBlend
[] = {
84 splashPipeResultColorNoAlphaBlendMono
,
85 splashPipeResultColorNoAlphaBlendMono
,
86 splashPipeResultColorNoAlphaBlendRGB
,
87 splashPipeResultColorNoAlphaBlendRGB
90 splashPipeResultColorNoAlphaBlendCMYK
94 SplashPipeResultColorCtrl
Splash::pipeResultColorAlphaNoBlend
[] = {
95 splashPipeResultColorAlphaNoBlendMono
,
96 splashPipeResultColorAlphaNoBlendMono
,
97 splashPipeResultColorAlphaNoBlendRGB
,
98 splashPipeResultColorAlphaNoBlendRGB
101 splashPipeResultColorAlphaNoBlendCMYK
105 SplashPipeResultColorCtrl
Splash::pipeResultColorAlphaBlend
[] = {
106 splashPipeResultColorAlphaBlendMono
,
107 splashPipeResultColorAlphaBlendMono
,
108 splashPipeResultColorAlphaBlendRGB
,
109 splashPipeResultColorAlphaBlendRGB
112 splashPipeResultColorAlphaBlendCMYK
116 //------------------------------------------------------------------------
118 static void blendXor(SplashColorPtr src
, SplashColorPtr dest
,
119 SplashColorPtr blend
, SplashColorMode cm
) {
122 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
123 blend
[i
] = src
[i
] ^ dest
[i
];
127 //------------------------------------------------------------------------
129 //------------------------------------------------------------------------
131 void Splash::clearModRegion() {
132 modXMin
= bitmap
->getWidth();
133 modYMin
= bitmap
->getHeight();
138 inline void Splash::updateModX(int x
) {
147 inline void Splash::updateModY(int y
) {
156 //------------------------------------------------------------------------
158 //------------------------------------------------------------------------
160 inline void Splash::pipeInit(SplashPipe
*pipe
, int x
, int y
,
161 SplashPattern
*pattern
, SplashColorPtr cSrc
,
162 SplashCoord aInput
, GBool usesShape
,
163 GBool nonIsolatedGroup
) {
164 pipeSetXY(pipe
, x
, y
);
165 pipe
->pattern
= NULL
;
169 if (pattern
->isStatic()) {
170 pattern
->getColor(x
, y
, pipe
->cSrcVal
);
172 pipe
->pattern
= pattern
;
174 pipe
->cSrc
= pipe
->cSrcVal
;
180 pipe
->aInput
= aInput
;
181 if (!state
->softMask
) {
185 pipe
->aSrc
= (Guchar
)splashRound(pipe
->aInput
* 255);
188 pipe
->usesShape
= usesShape
;
191 if (aInput
== 1 && !state
->softMask
&& !usesShape
&&
192 !state
->inNonIsolatedGroup
) {
193 pipe
->noTransparency
= gTrue
;
195 pipe
->noTransparency
= gFalse
;
199 if (pipe
->noTransparency
) {
200 // the !state->blendFunc case is handled separately in pipeRun
201 pipe
->resultColorCtrl
= pipeResultColorNoAlphaBlend
[bitmap
->mode
];
202 } else if (!state
->blendFunc
) {
203 pipe
->resultColorCtrl
= pipeResultColorAlphaNoBlend
[bitmap
->mode
];
205 pipe
->resultColorCtrl
= pipeResultColorAlphaBlend
[bitmap
->mode
];
208 // non-isolated group correction
209 if (nonIsolatedGroup
) {
210 pipe
->nonIsolatedGroup
= splashColorModeNComps
[bitmap
->mode
];
212 pipe
->nonIsolatedGroup
= 0;
216 inline void Splash::pipeRun(SplashPipe
*pipe
) {
217 Guchar aSrc
, aDest
, alpha2
, alpha0
, aResult
;
218 SplashColor cDest
, cBlend
;
219 Guchar cResult0
, cResult1
, cResult2
, cResult3
;
223 // static pattern: handled in pipeInit
224 // fixed color: handled in pipeInit
228 pipe
->pattern
->getColor(pipe
->x
, pipe
->y
, pipe
->cSrcVal
);
231 if (pipe
->noTransparency
&& !state
->blendFunc
) {
233 //----- write destination pixel
235 switch (bitmap
->mode
) {
236 case splashModeMono1
:
237 cResult0
= pipe
->cSrc
[0];
238 if (state
->screen
->test(pipe
->x
, pipe
->y
, cResult0
)) {
239 *pipe
->destColorPtr
|= pipe
->destColorMask
;
241 *pipe
->destColorPtr
&= ~pipe
->destColorMask
;
243 if (!(pipe
->destColorMask
>>= 1)) {
244 pipe
->destColorMask
= 0x80;
245 ++pipe
->destColorPtr
;
248 case splashModeMono8
:
249 *pipe
->destColorPtr
++ = pipe
->cSrc
[0];
252 *pipe
->destColorPtr
++ = pipe
->cSrc
[0];
253 *pipe
->destColorPtr
++ = pipe
->cSrc
[1];
254 *pipe
->destColorPtr
++ = pipe
->cSrc
[2];
257 *pipe
->destColorPtr
++ = pipe
->cSrc
[2];
258 *pipe
->destColorPtr
++ = pipe
->cSrc
[1];
259 *pipe
->destColorPtr
++ = pipe
->cSrc
[0];
262 case splashModeCMYK8
:
263 *pipe
->destColorPtr
++ = pipe
->cSrc
[0];
264 *pipe
->destColorPtr
++ = pipe
->cSrc
[1];
265 *pipe
->destColorPtr
++ = pipe
->cSrc
[2];
266 *pipe
->destColorPtr
++ = pipe
->cSrc
[3];
270 if (pipe
->destAlphaPtr
) {
271 *pipe
->destAlphaPtr
++ = 255;
276 //----- read destination pixel
278 switch (bitmap
->mode
) {
279 case splashModeMono1
:
280 cDest
[0] = (*pipe
->destColorPtr
& pipe
->destColorMask
) ? 0xff : 0x00;
282 case splashModeMono8
:
283 cDest
[0] = *pipe
->destColorPtr
;
286 cDest
[0] = pipe
->destColorPtr
[0];
287 cDest
[1] = pipe
->destColorPtr
[1];
288 cDest
[2] = pipe
->destColorPtr
[2];
291 cDest
[0] = pipe
->destColorPtr
[2];
292 cDest
[1] = pipe
->destColorPtr
[1];
293 cDest
[2] = pipe
->destColorPtr
[0];
296 case splashModeCMYK8
:
297 cDest
[0] = pipe
->destColorPtr
[0];
298 cDest
[1] = pipe
->destColorPtr
[1];
299 cDest
[2] = pipe
->destColorPtr
[2];
300 cDest
[3] = pipe
->destColorPtr
[3];
304 if (pipe
->destAlphaPtr
) {
305 aDest
= *pipe
->destAlphaPtr
;
310 //----- blend function
312 if (state
->blendFunc
) {
313 (*state
->blendFunc
)(pipe
->cSrc
, cDest
, cBlend
, bitmap
->mode
);
318 if (state
->softMask
) {
319 if (pipe
->usesShape
) {
320 aSrc
= (Guchar
)splashRound(pipe
->aInput
* *pipe
->softMaskPtr
++
323 aSrc
= (Guchar
)splashRound(pipe
->aInput
* *pipe
->softMaskPtr
++);
325 } else if (pipe
->usesShape
) {
326 // pipe->aInput is premultiplied by 255 in pipeInit
327 aSrc
= (Guchar
)splashRound(pipe
->aInput
* pipe
->shape
);
329 // precomputed in pipeInit
333 //----- result alpha and non-isolated group element correction
335 if (pipe
->noTransparency
) {
336 alpha2
= aResult
= 255;
338 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
340 if (pipe
->alpha0Ptr
) {
341 alpha0
= *pipe
->alpha0Ptr
++;
342 alpha2
= aResult
+ alpha0
- div255(aResult
* alpha0
);
350 cResult0
= cResult1
= cResult2
= cResult3
= 0; // make gcc happy
352 switch (pipe
->resultColorCtrl
) {
355 case splashPipeResultColorNoAlphaBlendCMYK
:
356 cResult3
= div255((255 - aDest
) * pipe
->cSrc
[3] + aDest
* cBlend
[3]);
358 case splashPipeResultColorNoAlphaBlendRGB
:
359 cResult2
= div255((255 - aDest
) * pipe
->cSrc
[2] + aDest
* cBlend
[2]);
360 cResult1
= div255((255 - aDest
) * pipe
->cSrc
[1] + aDest
* cBlend
[1]);
361 case splashPipeResultColorNoAlphaBlendMono
:
362 cResult0
= div255((255 - aDest
) * pipe
->cSrc
[0] + aDest
* cBlend
[0]);
365 case splashPipeResultColorAlphaNoBlendMono
:
369 cResult0
= (Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
370 aSrc
* pipe
->cSrc
[0]) / alpha2
);
373 case splashPipeResultColorAlphaNoBlendRGB
:
379 cResult0
= (Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
380 aSrc
* pipe
->cSrc
[0]) / alpha2
);
381 cResult1
= (Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
382 aSrc
* pipe
->cSrc
[1]) / alpha2
);
383 cResult2
= (Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
384 aSrc
* pipe
->cSrc
[2]) / alpha2
);
388 case splashPipeResultColorAlphaNoBlendCMYK
:
395 cResult0
= (Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
396 aSrc
* pipe
->cSrc
[0]) / alpha2
);
397 cResult1
= (Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
398 aSrc
* pipe
->cSrc
[1]) / alpha2
);
399 cResult2
= (Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
400 aSrc
* pipe
->cSrc
[2]) / alpha2
);
401 cResult3
= (Guchar
)(((alpha2
- aSrc
) * cDest
[3] +
402 aSrc
* pipe
->cSrc
[3]) / alpha2
);
407 case splashPipeResultColorAlphaBlendMono
:
411 cResult0
= (Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
412 aSrc
* ((255 - aDest
) * pipe
->cSrc
[0] +
413 aDest
* cBlend
[0]) / 255) /
417 case splashPipeResultColorAlphaBlendRGB
:
423 cResult0
= (Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
424 aSrc
* ((255 - aDest
) * pipe
->cSrc
[0] +
425 aDest
* cBlend
[0]) / 255) /
427 cResult1
= (Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
428 aSrc
* ((255 - aDest
) * pipe
->cSrc
[1] +
429 aDest
* cBlend
[1]) / 255) /
431 cResult2
= (Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
432 aSrc
* ((255 - aDest
) * pipe
->cSrc
[2] +
433 aDest
* cBlend
[2]) / 255) /
438 case splashPipeResultColorAlphaBlendCMYK
:
445 cResult0
= (Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
446 aSrc
* ((255 - aDest
) * pipe
->cSrc
[0] +
447 aDest
* cBlend
[0]) / 255) /
449 cResult1
= (Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
450 aSrc
* ((255 - aDest
) * pipe
->cSrc
[1] +
451 aDest
* cBlend
[1]) / 255) /
453 cResult2
= (Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
454 aSrc
* ((255 - aDest
) * pipe
->cSrc
[2] +
455 aDest
* cBlend
[2]) / 255) /
457 cResult3
= (Guchar
)(((alpha2
- aSrc
) * cDest
[3] +
458 aSrc
* ((255 - aDest
) * pipe
->cSrc
[3] +
459 aDest
* cBlend
[3]) / 255) /
466 //----- non-isolated group correction
469 switch (pipe
->nonIsolatedGroup
) {
472 cResult3
+= (cResult3
- cDest
[3]) * aDest
*
473 (255 - aResult
) / (255 * aResult
);
476 cResult2
+= (cResult2
- cDest
[2]) * aDest
*
477 (255 - aResult
) / (255 * aResult
);
478 cResult1
+= (cResult1
- cDest
[1]) * aDest
*
479 (255 - aResult
) / (255 * aResult
);
481 cResult0
+= (cResult0
- cDest
[0]) * aDest
*
482 (255 - aResult
) / (255 * aResult
);
488 //----- write destination pixel
490 switch (bitmap
->mode
) {
491 case splashModeMono1
:
492 if (state
->screen
->test(pipe
->x
, pipe
->y
, cResult0
)) {
493 *pipe
->destColorPtr
|= pipe
->destColorMask
;
495 *pipe
->destColorPtr
&= ~pipe
->destColorMask
;
497 if (!(pipe
->destColorMask
>>= 1)) {
498 pipe
->destColorMask
= 0x80;
499 ++pipe
->destColorPtr
;
502 case splashModeMono8
:
503 *pipe
->destColorPtr
++ = cResult0
;
506 *pipe
->destColorPtr
++ = cResult0
;
507 *pipe
->destColorPtr
++ = cResult1
;
508 *pipe
->destColorPtr
++ = cResult2
;
511 *pipe
->destColorPtr
++ = cResult2
;
512 *pipe
->destColorPtr
++ = cResult1
;
513 *pipe
->destColorPtr
++ = cResult0
;
516 case splashModeCMYK8
:
517 *pipe
->destColorPtr
++ = cResult0
;
518 *pipe
->destColorPtr
++ = cResult1
;
519 *pipe
->destColorPtr
++ = cResult2
;
520 *pipe
->destColorPtr
++ = cResult3
;
524 if (pipe
->destAlphaPtr
) {
525 *pipe
->destAlphaPtr
++ = aResult
;
533 inline void Splash::pipeSetXY(SplashPipe
*pipe
, int x
, int y
) {
536 if (state
->softMask
) {
538 &state
->softMask
->data
[y
* state
->softMask
->rowSize
+ x
];
540 switch (bitmap
->mode
) {
541 case splashModeMono1
:
542 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ (x
>> 3)];
543 pipe
->destColorMask
= 0x80 >> (x
& 7);
545 case splashModeMono8
:
546 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ x
];
550 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ 3 * x
];
553 case splashModeCMYK8
:
554 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ 4 * x
];
559 pipe
->destAlphaPtr
= &bitmap
->alpha
[y
* bitmap
->width
+ x
];
561 pipe
->destAlphaPtr
= NULL
;
563 if (state
->inNonIsolatedGroup
&& alpha0Bitmap
->alpha
) {
565 &alpha0Bitmap
->alpha
[(alpha0Y
+ y
) * alpha0Bitmap
->width
+
568 pipe
->alpha0Ptr
= NULL
;
572 inline void Splash::pipeIncX(SplashPipe
*pipe
) {
574 if (state
->softMask
) {
577 switch (bitmap
->mode
) {
578 case splashModeMono1
:
579 if (!(pipe
->destColorMask
>>= 1)) {
580 pipe
->destColorMask
= 0x80;
581 ++pipe
->destColorPtr
;
584 case splashModeMono8
:
585 ++pipe
->destColorPtr
;
589 pipe
->destColorPtr
+= 3;
592 case splashModeCMYK8
:
593 pipe
->destColorPtr
+= 4;
597 if (pipe
->destAlphaPtr
) {
598 ++pipe
->destAlphaPtr
;
600 if (pipe
->alpha0Ptr
) {
605 inline void Splash::drawPixel(SplashPipe
*pipe
, int x
, int y
, GBool noClip
) {
606 if (noClip
|| state
->clip
->test(x
, y
)) {
607 pipeSetXY(pipe
, x
, y
);
614 inline void Splash::drawAAPixelInit() {
618 inline void Splash::drawAAPixel(SplashPipe
*pipe
, int x
, int y
) {
619 #if splashAASize == 4
620 static int bitCount4
[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
621 1, 2, 2, 3, 2, 3, 3, 4 };
629 if (x
< 0 || x
>= bitmap
->width
||
630 y
< state
->clip
->getYMinI() || y
> state
->clip
->getYMaxI()) {
636 memset(aaBuf
->getDataPtr(), 0xff,
637 aaBuf
->getRowSize() * aaBuf
->getHeight());
639 x1
= bitmap
->width
- 1;
640 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
);
644 // compute the shape value
645 #if splashAASize == 4
646 p
= aaBuf
->getDataPtr() + (x
>> 1);
647 w
= aaBuf
->getRowSize();
649 t
= bitCount4
[*p
& 0x0f] + bitCount4
[p
[w
] & 0x0f] +
650 bitCount4
[p
[2*w
] & 0x0f] + bitCount4
[p
[3*w
] & 0x0f];
652 t
= bitCount4
[*p
>> 4] + bitCount4
[p
[w
] >> 4] +
653 bitCount4
[p
[2*w
] >> 4] + bitCount4
[p
[3*w
] >> 4];
657 for (yy
= 0; yy
< splashAASize
; ++yy
) {
658 for (xx
= 0; xx
< splashAASize
; ++xx
) {
659 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() +
660 ((x
* splashAASize
+ xx
) >> 3);
661 t
+= (*p
>> (7 - ((x
* splashAASize
+ xx
) & 7))) & 1;
668 pipeSetXY(pipe
, x
, y
);
669 pipe
->shape
*= aaGamma
[t
];
676 inline void Splash::drawSpan(SplashPipe
*pipe
, int x0
, int x1
, int y
,
680 pipeSetXY(pipe
, x0
, y
);
682 for (x
= x0
; x
<= x1
; ++x
) {
689 for (x
= x0
; x
<= x1
; ++x
) {
690 if (state
->clip
->test(x
, y
)) {
701 inline void Splash::drawAALine(SplashPipe
*pipe
, int x0
, int x1
, int y
) {
702 #if splashAASize == 4
703 static int bitCount4
[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
704 1, 2, 2, 3, 2, 3, 3, 4 };
705 SplashColorPtr p0
, p1
, p2
, p3
;
713 #if splashAASize == 4
714 p0
= aaBuf
->getDataPtr() + (x0
>> 1);
715 p1
= p0
+ aaBuf
->getRowSize();
716 p2
= p1
+ aaBuf
->getRowSize();
717 p3
= p2
+ aaBuf
->getRowSize();
719 pipeSetXY(pipe
, x0
, y
);
720 for (x
= x0
; x
<= x1
; ++x
) {
722 // compute the shape value
723 #if splashAASize == 4
725 t
= bitCount4
[*p0
& 0x0f] + bitCount4
[*p1
& 0x0f] +
726 bitCount4
[*p2
& 0x0f] + bitCount4
[*p3
& 0x0f];
727 ++p0
; ++p1
; ++p2
; ++p3
;
729 t
= bitCount4
[*p0
>> 4] + bitCount4
[*p1
>> 4] +
730 bitCount4
[*p2
>> 4] + bitCount4
[*p3
>> 4];
734 for (yy
= 0; yy
< splashAASize
; ++yy
) {
735 for (xx
= 0; xx
< splashAASize
; ++xx
) {
736 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() +
737 ((x
* splashAASize
+ xx
) >> 3);
738 t
+= (*p
>> (7 - ((x
* splashAASize
+ xx
) & 7))) & 1;
744 pipe
->shape
= aaGamma
[t
];
754 //------------------------------------------------------------------------
756 // Transform a point from user space to device space.
757 inline void Splash::transform(SplashCoord
*matrix
,
758 SplashCoord xi
, SplashCoord yi
,
759 SplashCoord
*xo
, SplashCoord
*yo
) {
761 // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
763 *xo
= xi
* matrix
[0] + yi
* matrix
[2] + matrix
[4];
764 *yo
= xi
* matrix
[1] + yi
* matrix
[3] + matrix
[5];
767 //------------------------------------------------------------------------
769 //------------------------------------------------------------------------
771 Splash::Splash(SplashBitmap
*bitmapA
, GBool vectorAntialiasA
,
772 SplashScreenParams
*screenParams
) {
776 vectorAntialias
= vectorAntialiasA
;
777 state
= new SplashState(bitmap
->width
, bitmap
->height
, vectorAntialias
,
779 if (vectorAntialias
) {
780 aaBuf
= new SplashBitmap(splashAASize
* bitmap
->width
, splashAASize
,
781 1, splashModeMono1
, gFalse
);
782 for (i
= 0; i
<= splashAASize
* splashAASize
; ++i
) {
783 aaGamma
[i
] = splashPow((SplashCoord
)i
/
784 (SplashCoord
)(splashAASize
* splashAASize
),
794 Splash::Splash(SplashBitmap
*bitmapA
, GBool vectorAntialiasA
,
795 SplashScreen
*screenA
) {
799 vectorAntialias
= vectorAntialiasA
;
800 state
= new SplashState(bitmap
->width
, bitmap
->height
, vectorAntialias
,
802 if (vectorAntialias
) {
803 aaBuf
= new SplashBitmap(splashAASize
* bitmap
->width
, splashAASize
,
804 1, splashModeMono1
, gFalse
);
805 for (i
= 0; i
<= splashAASize
* splashAASize
; ++i
) {
806 aaGamma
[i
] = splashPow((SplashCoord
)i
/
807 (SplashCoord
)(splashAASize
* splashAASize
),
818 while (state
->next
) {
822 if (vectorAntialias
) {
827 //------------------------------------------------------------------------
829 //------------------------------------------------------------------------
831 SplashCoord
*Splash::getMatrix() {
832 return state
->matrix
;
835 SplashPattern
*Splash::getStrokePattern() {
836 return state
->strokePattern
;
839 SplashPattern
*Splash::getFillPattern() {
840 return state
->fillPattern
;
843 SplashScreen
*Splash::getScreen() {
844 return state
->screen
;
847 SplashBlendFunc
Splash::getBlendFunc() {
848 return state
->blendFunc
;
851 SplashCoord
Splash::getStrokeAlpha() {
852 return state
->strokeAlpha
;
855 SplashCoord
Splash::getFillAlpha() {
856 return state
->fillAlpha
;
859 SplashCoord
Splash::getLineWidth() {
860 return state
->lineWidth
;
863 int Splash::getLineCap() {
864 return state
->lineCap
;
867 int Splash::getLineJoin() {
868 return state
->lineJoin
;
871 SplashCoord
Splash::getMiterLimit() {
872 return state
->miterLimit
;
875 SplashCoord
Splash::getFlatness() {
876 return state
->flatness
;
879 SplashCoord
*Splash::getLineDash() {
880 return state
->lineDash
;
883 int Splash::getLineDashLength() {
884 return state
->lineDashLength
;
887 SplashCoord
Splash::getLineDashPhase() {
888 return state
->lineDashPhase
;
891 SplashClip
*Splash::getClip() {
895 SplashBitmap
*Splash::getSoftMask() {
896 return state
->softMask
;
899 GBool
Splash::getInNonIsolatedGroup() {
900 return state
->inNonIsolatedGroup
;
903 //------------------------------------------------------------------------
905 //------------------------------------------------------------------------
907 void Splash::setMatrix(SplashCoord
*matrix
) {
908 memcpy(state
->matrix
, matrix
, 6 * sizeof(SplashCoord
));
911 void Splash::setStrokePattern(SplashPattern
*strokePattern
) {
912 state
->setStrokePattern(strokePattern
);
915 void Splash::setFillPattern(SplashPattern
*fillPattern
) {
916 state
->setFillPattern(fillPattern
);
919 void Splash::setScreen(SplashScreen
*screen
) {
920 state
->setScreen(screen
);
923 void Splash::setBlendFunc(SplashBlendFunc func
) {
924 state
->blendFunc
= func
;
927 void Splash::setStrokeAlpha(SplashCoord alpha
) {
928 state
->strokeAlpha
= alpha
;
931 void Splash::setFillAlpha(SplashCoord alpha
) {
932 state
->fillAlpha
= alpha
;
935 void Splash::setLineWidth(SplashCoord lineWidth
) {
936 state
->lineWidth
= lineWidth
;
939 void Splash::setLineCap(int lineCap
) {
940 state
->lineCap
= lineCap
;
943 void Splash::setLineJoin(int lineJoin
) {
944 state
->lineJoin
= lineJoin
;
947 void Splash::setMiterLimit(SplashCoord miterLimit
) {
948 state
->miterLimit
= miterLimit
;
951 void Splash::setFlatness(SplashCoord flatness
) {
955 state
->flatness
= flatness
;
959 void Splash::setLineDash(SplashCoord
*lineDash
, int lineDashLength
,
960 SplashCoord lineDashPhase
) {
961 state
->setLineDash(lineDash
, lineDashLength
, lineDashPhase
);
964 void Splash::setStrokeAdjust(GBool strokeAdjust
) {
965 state
->strokeAdjust
= strokeAdjust
;
968 void Splash::clipResetToRect(SplashCoord x0
, SplashCoord y0
,
969 SplashCoord x1
, SplashCoord y1
) {
970 state
->clip
->resetToRect(x0
, y0
, x1
, y1
);
973 SplashError
Splash::clipToRect(SplashCoord x0
, SplashCoord y0
,
974 SplashCoord x1
, SplashCoord y1
) {
975 return state
->clip
->clipToRect(x0
, y0
, x1
, y1
);
978 SplashError
Splash::clipToPath(SplashPath
*path
, GBool eo
) {
979 return state
->clip
->clipToPath(path
, state
->matrix
, state
->flatness
, eo
);
982 void Splash::setSoftMask(SplashBitmap
*softMask
) {
983 state
->setSoftMask(softMask
);
986 void Splash::setInNonIsolatedGroup(SplashBitmap
*alpha0BitmapA
,
987 int alpha0XA
, int alpha0YA
) {
988 alpha0Bitmap
= alpha0BitmapA
;
991 state
->inNonIsolatedGroup
= gTrue
;
994 //------------------------------------------------------------------------
995 // state save/restore
996 //------------------------------------------------------------------------
998 void Splash::saveState() {
999 SplashState
*newState
;
1001 newState
= state
->copy();
1002 newState
->next
= state
;
1006 SplashError
Splash::restoreState() {
1007 SplashState
*oldState
;
1010 return splashErrNoSave
;
1013 state
= state
->next
;
1018 //------------------------------------------------------------------------
1019 // drawing operations
1020 //------------------------------------------------------------------------
1022 void Splash::clear(SplashColorPtr color
, Guchar alpha
) {
1023 SplashColorPtr row
, p
;
1027 switch (bitmap
->mode
) {
1028 case splashModeMono1
:
1029 mono
= (color
[0] & 0x80) ? 0xff : 0x00;
1030 if (bitmap
->rowSize
< 0) {
1031 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1032 mono
, -bitmap
->rowSize
* bitmap
->height
);
1034 memset(bitmap
->data
, mono
, bitmap
->rowSize
* bitmap
->height
);
1037 case splashModeMono8
:
1038 if (bitmap
->rowSize
< 0) {
1039 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1040 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1042 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1045 case splashModeRGB8
:
1046 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1047 if (bitmap
->rowSize
< 0) {
1048 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1049 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1051 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1055 for (y
= 0; y
< bitmap
->height
; ++y
) {
1057 for (x
= 0; x
< bitmap
->width
; ++x
) {
1062 row
+= bitmap
->rowSize
;
1066 case splashModeBGR8
:
1067 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1068 if (bitmap
->rowSize
< 0) {
1069 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1070 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1072 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1076 for (y
= 0; y
< bitmap
->height
; ++y
) {
1078 for (x
= 0; x
< bitmap
->width
; ++x
) {
1083 row
+= bitmap
->rowSize
;
1088 case splashModeCMYK8
:
1089 if (color
[0] == color
[1] && color
[1] == color
[2] && color
[2] == color
[3]) {
1090 if (bitmap
->rowSize
< 0) {
1091 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1092 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1094 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1098 for (y
= 0; y
< bitmap
->height
; ++y
) {
1100 for (x
= 0; x
< bitmap
->width
; ++x
) {
1106 row
+= bitmap
->rowSize
;
1113 if (bitmap
->alpha
) {
1114 memset(bitmap
->alpha
, alpha
, bitmap
->width
* bitmap
->height
);
1119 updateModX(bitmap
->width
- 1);
1120 updateModY(bitmap
->height
- 1);
1123 SplashError
Splash::stroke(SplashPath
*path
) {
1124 SplashPath
*path2
, *dPath
;
1127 printf("stroke [dash:%d] [width:%.2f]:\n",
1128 state
->lineDashLength
, (double)state
->lineWidth
);
1131 opClipRes
= splashClipAllOutside
;
1132 if (path
->length
== 0) {
1133 return splashErrEmptyPath
;
1135 path2
= flattenPath(path
, state
->matrix
, state
->flatness
);
1136 if (state
->lineDashLength
> 0) {
1137 dPath
= makeDashedPath(path2
);
1141 if (state
->lineWidth
== 0) {
1142 strokeNarrow(path2
);
1150 void Splash::strokeNarrow(SplashPath
*path
) {
1153 SplashXPathSeg
*seg
;
1154 int x0
, x1
, x2
, x3
, y0
, y1
, x
, y
, t
;
1155 SplashCoord dx
, dy
, dxdy
;
1156 SplashClipResult clipRes
;
1160 nClipRes
[0] = nClipRes
[1] = nClipRes
[2] = 0;
1162 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gFalse
);
1164 pipeInit(&pipe
, 0, 0, state
->strokePattern
, NULL
, state
->strokeAlpha
,
1167 for (i
= 0, seg
= xPath
->segs
; i
< xPath
->length
; ++i
, ++seg
) {
1169 x0
= splashFloor(seg
->x0
);
1170 x1
= splashFloor(seg
->x1
);
1171 y0
= splashFloor(seg
->y0
);
1172 y1
= splashFloor(seg
->y1
);
1174 // horizontal segment
1177 t
= x0
; x0
= x1
; x1
= t
;
1179 if ((clipRes
= state
->clip
->testSpan(x0
, x1
, y0
))
1180 != splashClipAllOutside
) {
1181 drawSpan(&pipe
, x0
, x1
, y0
, clipRes
== splashClipAllInside
);
1184 // segment with |dx| > |dy|
1185 } else if (splashAbs(seg
->dxdy
) > 1) {
1186 dx
= seg
->x1
- seg
->x0
;
1187 dy
= seg
->y1
- seg
->y0
;
1190 t
= y0
; y0
= y1
; y1
= t
;
1191 t
= x0
; x0
= x1
; x1
= t
;
1195 if ((clipRes
= state
->clip
->testRect(x0
<= x1
? x0
: x1
, y0
,
1196 x0
<= x1
? x1
: x0
, y1
))
1197 != splashClipAllOutside
) {
1200 x3
= splashFloor(seg
->x0
+ ((SplashCoord
)y0
+ 1 - seg
->y0
) * dxdy
);
1201 drawSpan(&pipe
, x2
, (x2
<= x3
- 1) ? x3
- 1 : x2
, y0
,
1202 clipRes
== splashClipAllInside
);
1204 for (y
= y0
+ 1; y
<= y1
- 1; ++y
) {
1205 x3
= splashFloor(seg
->x0
+ ((SplashCoord
)y
+ 1 - seg
->y0
) * dxdy
);
1206 drawSpan(&pipe
, x2
, x3
- 1, y
, clipRes
== splashClipAllInside
);
1209 drawSpan(&pipe
, x2
, x2
<= x1
? x1
: x2
, y1
,
1210 clipRes
== splashClipAllInside
);
1213 x3
= splashFloor(seg
->x0
+ ((SplashCoord
)y0
+ 1 - seg
->y0
) * dxdy
);
1214 drawSpan(&pipe
, (x3
+ 1 <= x2
) ? x3
+ 1 : x2
, x2
, y0
,
1215 clipRes
== splashClipAllInside
);
1217 for (y
= y0
+ 1; y
<= y1
- 1; ++y
) {
1218 x3
= splashFloor(seg
->x0
+ ((SplashCoord
)y
+ 1 - seg
->y0
) * dxdy
);
1219 drawSpan(&pipe
, x3
+ 1, x2
, y
, clipRes
== splashClipAllInside
);
1222 drawSpan(&pipe
, x1
, (x1
<= x2
) ? x2
: x1
, y1
,
1223 clipRes
== splashClipAllInside
);
1227 // segment with |dy| > |dx|
1231 t
= x0
; x0
= x1
; x1
= t
;
1232 t
= y0
; y0
= y1
; y1
= t
;
1234 if ((clipRes
= state
->clip
->testRect(x0
<= x1
? x0
: x1
, y0
,
1235 x0
<= x1
? x1
: x0
, y1
))
1236 != splashClipAllOutside
) {
1237 drawPixel(&pipe
, x0
, y0
, clipRes
== splashClipAllInside
);
1238 for (y
= y0
+ 1; y
<= y1
- 1; ++y
) {
1239 x
= splashFloor(seg
->x0
+ ((SplashCoord
)y
- seg
->y0
) * dxdy
);
1240 drawPixel(&pipe
, x
, y
, clipRes
== splashClipAllInside
);
1242 drawPixel(&pipe
, x1
, y1
, clipRes
== splashClipAllInside
);
1245 ++nClipRes
[clipRes
];
1247 if (nClipRes
[splashClipPartial
] ||
1248 (nClipRes
[splashClipAllInside
] && nClipRes
[splashClipAllOutside
])) {
1249 opClipRes
= splashClipPartial
;
1250 } else if (nClipRes
[splashClipAllInside
]) {
1251 opClipRes
= splashClipAllInside
;
1253 opClipRes
= splashClipAllOutside
;
1259 void Splash::strokeWide(SplashPath
*path
) {
1262 path2
= makeStrokePath(path
, gFalse
);
1263 fillWithPattern(path2
, gFalse
, state
->strokePattern
, state
->strokeAlpha
);
1267 SplashPath
*Splash::flattenPath(SplashPath
*path
, SplashCoord
*matrix
,
1268 SplashCoord flatness
) {
1270 SplashCoord flatness2
;
1274 fPath
= new SplashPath();
1275 flatness2
= flatness
* flatness
;
1277 while (i
< path
->length
) {
1278 flag
= path
->flags
[i
];
1279 if (flag
& splashPathFirst
) {
1280 fPath
->moveTo(path
->pts
[i
].x
, path
->pts
[i
].y
);
1283 if (flag
& splashPathCurve
) {
1284 flattenCurve(path
->pts
[i
-1].x
, path
->pts
[i
-1].y
,
1285 path
->pts
[i
].x
, path
->pts
[i
].y
,
1286 path
->pts
[i
+1].x
, path
->pts
[i
+1].y
,
1287 path
->pts
[i
+2].x
, path
->pts
[i
+2].y
,
1288 matrix
, flatness2
, fPath
);
1291 fPath
->lineTo(path
->pts
[i
].x
, path
->pts
[i
].y
);
1294 if (path
->flags
[i
-1] & splashPathClosed
) {
1302 void Splash::flattenCurve(SplashCoord x0
, SplashCoord y0
,
1303 SplashCoord x1
, SplashCoord y1
,
1304 SplashCoord x2
, SplashCoord y2
,
1305 SplashCoord x3
, SplashCoord y3
,
1306 SplashCoord
*matrix
, SplashCoord flatness2
,
1307 SplashPath
*fPath
) {
1308 SplashCoord cx
[splashMaxCurveSplits
+ 1][3];
1309 SplashCoord cy
[splashMaxCurveSplits
+ 1][3];
1310 int cNext
[splashMaxCurveSplits
+ 1];
1311 SplashCoord xl0
, xl1
, xl2
, xr0
, xr1
, xr2
, xr3
, xx1
, xx2
, xh
;
1312 SplashCoord yl0
, yl1
, yl2
, yr0
, yr1
, yr2
, yr3
, yy1
, yy2
, yh
;
1313 SplashCoord dx
, dy
, mx
, my
, tx
, ty
, d1
, d2
;
1318 p2
= splashMaxCurveSplits
;
1319 cx
[p1
][0] = x0
; cy
[p1
][0] = y0
;
1320 cx
[p1
][1] = x1
; cy
[p1
][1] = y1
;
1321 cx
[p1
][2] = x2
; cy
[p1
][2] = y2
;
1322 cx
[p2
][0] = x3
; cy
[p2
][0] = y3
;
1325 while (p1
< splashMaxCurveSplits
) {
1327 // get the next segment
1328 xl0
= cx
[p1
][0]; yl0
= cy
[p1
][0];
1329 xx1
= cx
[p1
][1]; yy1
= cy
[p1
][1];
1330 xx2
= cx
[p1
][2]; yy2
= cy
[p1
][2];
1332 xr3
= cx
[p2
][0]; yr3
= cy
[p2
][0];
1334 // compute the distances (in device space) from the control points
1335 // to the midpoint of the straight line (this is a bit of a hack,
1336 // but it's much faster than computing the actual distances to the
1338 transform(matrix
, (xl0
+ xr3
) * 0.5, (yl0
+ yr3
) * 0.5, &mx
, &my
);
1339 transform(matrix
, xx1
, yy1
, &tx
, &ty
);
1343 transform(matrix
, xx2
, yy2
, &tx
, &ty
);
1348 // if the curve is flat enough, or no more subdivisions are
1349 // allowed, add the straight line segment
1350 if (p2
- p1
== 1 || (d1
<= flatness2
&& d2
<= flatness2
)) {
1351 fPath
->lineTo(xr3
, yr3
);
1354 // otherwise, subdivide the curve
1356 xl1
= (xl0
+ xx1
) * 0.5;
1357 yl1
= (yl0
+ yy1
) * 0.5;
1358 xh
= (xx1
+ xx2
) * 0.5;
1359 yh
= (yy1
+ yy2
) * 0.5;
1360 xl2
= (xl1
+ xh
) * 0.5;
1361 yl2
= (yl1
+ yh
) * 0.5;
1362 xr2
= (xx2
+ xr3
) * 0.5;
1363 yr2
= (yy2
+ yr3
) * 0.5;
1364 xr1
= (xh
+ xr2
) * 0.5;
1365 yr1
= (yh
+ yr2
) * 0.5;
1366 xr0
= (xl2
+ xr1
) * 0.5;
1367 yr0
= (yl2
+ yr1
) * 0.5;
1368 // add the new subdivision points
1370 cx
[p1
][1] = xl1
; cy
[p1
][1] = yl1
;
1371 cx
[p1
][2] = xl2
; cy
[p1
][2] = yl2
;
1373 cx
[p3
][0] = xr0
; cy
[p3
][0] = yr0
;
1374 cx
[p3
][1] = xr1
; cy
[p3
][1] = yr1
;
1375 cx
[p3
][2] = xr2
; cy
[p3
][2] = yr2
;
1381 SplashPath
*Splash::makeDashedPath(SplashPath
*path
) {
1383 SplashCoord lineDashTotal
;
1384 SplashCoord lineDashStartPhase
, lineDashDist
, segLen
;
1385 SplashCoord x0
, y0
, x1
, y1
, xa
, ya
;
1386 GBool lineDashStartOn
, lineDashOn
, newPath
;
1387 int lineDashStartIdx
, lineDashIdx
;
1391 for (i
= 0; i
< state
->lineDashLength
; ++i
) {
1392 lineDashTotal
+= state
->lineDash
[i
];
1394 lineDashStartPhase
= state
->lineDashPhase
;
1395 i
= splashFloor(lineDashStartPhase
/ lineDashTotal
);
1396 lineDashStartPhase
-= (SplashCoord
)i
* lineDashTotal
;
1397 lineDashStartOn
= gTrue
;
1398 lineDashStartIdx
= 0;
1399 while (lineDashStartPhase
>= state
->lineDash
[lineDashStartIdx
]) {
1400 lineDashStartOn
= !lineDashStartOn
;
1401 lineDashStartPhase
-= state
->lineDash
[lineDashStartIdx
];
1405 dPath
= new SplashPath();
1407 // process each subpath
1409 while (i
< path
->length
) {
1411 // find the end of the subpath
1413 j
< path
->length
- 1 && !(path
->flags
[j
] & splashPathLast
);
1416 // initialize the dash parameters
1417 lineDashOn
= lineDashStartOn
;
1418 lineDashIdx
= lineDashStartIdx
;
1419 lineDashDist
= state
->lineDash
[lineDashIdx
] - lineDashStartPhase
;
1421 // process each segment of the subpath
1423 for (k
= i
; k
< j
; ++k
) {
1426 x0
= path
->pts
[k
].x
;
1427 y0
= path
->pts
[k
].y
;
1428 x1
= path
->pts
[k
+1].x
;
1429 y1
= path
->pts
[k
+1].y
;
1430 segLen
= splashDist(x0
, y0
, x1
, y1
);
1432 // process the segment
1433 while (segLen
> 0) {
1435 if (lineDashDist
>= segLen
) {
1438 dPath
->moveTo(x0
, y0
);
1441 dPath
->lineTo(x1
, y1
);
1443 lineDashDist
-= segLen
;
1447 xa
= x0
+ (lineDashDist
/ segLen
) * (x1
- x0
);
1448 ya
= y0
+ (lineDashDist
/ segLen
) * (y1
- y0
);
1451 dPath
->moveTo(x0
, y0
);
1454 dPath
->lineTo(xa
, ya
);
1458 segLen
-= lineDashDist
;
1462 // get the next entry in the dash array
1463 if (lineDashDist
<= 0) {
1464 lineDashOn
= !lineDashOn
;
1465 if (++lineDashIdx
== state
->lineDashLength
) {
1468 lineDashDist
= state
->lineDash
[lineDashIdx
];
1479 SplashError
Splash::fill(SplashPath
*path
, GBool eo
) {
1481 printf("fill [eo:%d]:\n", eo
);
1484 return fillWithPattern(path
, eo
, state
->fillPattern
, state
->fillAlpha
);
1487 SplashError
Splash::fillWithPattern(SplashPath
*path
, GBool eo
,
1488 SplashPattern
*pattern
,
1489 SplashCoord alpha
) {
1492 SplashXPathScanner
*scanner
;
1493 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
1494 SplashClipResult clipRes
, clipRes2
;
1496 if (path
->length
== 0) {
1497 return splashErrEmptyPath
;
1499 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
);
1500 if (vectorAntialias
) {
1504 scanner
= new SplashXPathScanner(xPath
, eo
);
1506 // get the min and max x and y values
1507 if (vectorAntialias
) {
1508 scanner
->getBBoxAA(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
1510 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
1514 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
))
1515 != splashClipAllOutside
) {
1517 // limit the y range
1518 if (yMinI
< state
->clip
->getYMinI()) {
1519 yMinI
= state
->clip
->getYMinI();
1521 if (yMaxI
> state
->clip
->getYMaxI()) {
1522 yMaxI
= state
->clip
->getYMaxI();
1525 pipeInit(&pipe
, 0, yMinI
, pattern
, NULL
, alpha
, vectorAntialias
, gFalse
);
1528 if (vectorAntialias
) {
1529 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
1530 scanner
->renderAALine(aaBuf
, &x0
, &x1
, y
);
1531 if (clipRes
!= splashClipAllInside
) {
1532 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
);
1534 drawAALine(&pipe
, x0
, x1
, y
);
1537 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
1538 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
1539 if (clipRes
== splashClipAllInside
) {
1540 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
1542 // limit the x range
1543 if (x0
< state
->clip
->getXMinI()) {
1544 x0
= state
->clip
->getXMinI();
1546 if (x1
> state
->clip
->getXMaxI()) {
1547 x1
= state
->clip
->getXMaxI();
1549 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
1550 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
1556 opClipRes
= clipRes
;
1563 SplashError
Splash::xorFill(SplashPath
*path
, GBool eo
) {
1566 SplashXPathScanner
*scanner
;
1567 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
1568 SplashClipResult clipRes
, clipRes2
;
1569 SplashBlendFunc origBlendFunc
;
1571 if (path
->length
== 0) {
1572 return splashErrEmptyPath
;
1574 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
);
1576 scanner
= new SplashXPathScanner(xPath
, eo
);
1578 // get the min and max x and y values
1579 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
1582 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
))
1583 != splashClipAllOutside
) {
1585 // limit the y range
1586 if (yMinI
< state
->clip
->getYMinI()) {
1587 yMinI
= state
->clip
->getYMinI();
1589 if (yMaxI
> state
->clip
->getYMaxI()) {
1590 yMaxI
= state
->clip
->getYMaxI();
1593 origBlendFunc
= state
->blendFunc
;
1594 state
->blendFunc
= &blendXor
;
1595 pipeInit(&pipe
, 0, yMinI
, state
->fillPattern
, NULL
, 1, gFalse
, gFalse
);
1598 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
1599 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
1600 if (clipRes
== splashClipAllInside
) {
1601 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
1603 // limit the x range
1604 if (x0
< state
->clip
->getXMinI()) {
1605 x0
= state
->clip
->getXMinI();
1607 if (x1
> state
->clip
->getXMaxI()) {
1608 x1
= state
->clip
->getXMaxI();
1610 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
1611 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
1615 state
->blendFunc
= origBlendFunc
;
1617 opClipRes
= clipRes
;
1624 SplashError
Splash::fillChar(SplashCoord x
, SplashCoord y
,
1625 int c
, SplashFont
*font
) {
1626 SplashGlyphBitmap glyph
;
1628 int x0
, y0
, xFrac
, yFrac
;
1632 printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
1633 (double)x
, (double)y
, c
, c
, c
);
1635 transform(state
->matrix
, x
, y
, &xt
, &yt
);
1636 x0
= splashFloor(xt
);
1637 xFrac
= splashFloor((xt
- x0
) * splashFontFraction
);
1638 y0
= splashFloor(yt
);
1639 yFrac
= splashFloor((yt
- y0
) * splashFontFraction
);
1640 if (!font
->getGlyph(c
, xFrac
, yFrac
, &glyph
)) {
1641 return splashErrNoGlyph
;
1643 err
= fillGlyph2(x0
, y0
, &glyph
);
1644 if (glyph
.freeData
) {
1650 SplashError
Splash::fillGlyph(SplashCoord x
, SplashCoord y
,
1651 SplashGlyphBitmap
*glyph
) {
1655 transform(state
->matrix
, x
, y
, &xt
, &yt
);
1656 x0
= splashFloor(xt
);
1657 y0
= splashFloor(yt
);
1658 return fillGlyph2(x0
, y0
, glyph
);
1661 SplashError
Splash::fillGlyph2(int x0
, int y0
, SplashGlyphBitmap
*glyph
) {
1663 SplashClipResult clipRes
;
1667 int x1
, y1
, xx
, xx1
, yy
;
1669 if ((clipRes
= state
->clip
->testRect(x0
- glyph
->x
,
1671 x0
- glyph
->x
+ glyph
->w
- 1,
1672 y0
- glyph
->y
+ glyph
->h
- 1))
1673 != splashClipAllOutside
) {
1674 noClip
= clipRes
== splashClipAllInside
;
1678 pipeInit(&pipe
, x0
- glyph
->x
, y0
- glyph
->y
,
1679 state
->fillPattern
, NULL
, state
->fillAlpha
, gTrue
, gFalse
);
1681 for (yy
= 0, y1
= y0
- glyph
->y
; yy
< glyph
->h
; ++yy
, ++y1
) {
1682 pipeSetXY(&pipe
, x0
- glyph
->x
, y1
);
1683 for (xx
= 0, x1
= x0
- glyph
->x
; xx
< glyph
->w
; ++xx
, ++x1
) {
1686 pipe
.shape
= (SplashCoord
)(alpha
/ 255.0);
1696 pipeInit(&pipe
, x0
- glyph
->x
, y0
- glyph
->y
,
1697 state
->fillPattern
, NULL
, state
->fillAlpha
, gFalse
, gFalse
);
1699 for (yy
= 0, y1
= y0
- glyph
->y
; yy
< glyph
->h
; ++yy
, ++y1
) {
1700 pipeSetXY(&pipe
, x0
- glyph
->x
, y1
);
1701 for (xx
= 0, x1
= x0
- glyph
->x
; xx
< glyph
->w
; xx
+= 8) {
1703 for (xx1
= 0; xx1
< 8 && xx
+ xx1
< glyph
->w
; ++xx1
, ++x1
) {
1704 if (alpha0
& 0x80) {
1718 pipeInit(&pipe
, x0
- glyph
->x
, y0
- glyph
->y
,
1719 state
->fillPattern
, NULL
, state
->fillAlpha
, gTrue
, gFalse
);
1721 for (yy
= 0, y1
= y0
- glyph
->y
; yy
< glyph
->h
; ++yy
, ++y1
) {
1722 pipeSetXY(&pipe
, x0
- glyph
->x
, y1
);
1723 for (xx
= 0, x1
= x0
- glyph
->x
; xx
< glyph
->w
; ++xx
, ++x1
) {
1724 if (state
->clip
->test(x1
, y1
)) {
1727 pipe
.shape
= (SplashCoord
)(alpha
/ 255.0);
1741 pipeInit(&pipe
, x0
- glyph
->x
, y0
- glyph
->y
,
1742 state
->fillPattern
, NULL
, state
->fillAlpha
, gFalse
, gFalse
);
1744 for (yy
= 0, y1
= y0
- glyph
->y
; yy
< glyph
->h
; ++yy
, ++y1
) {
1745 pipeSetXY(&pipe
, x0
- glyph
->x
, y1
);
1746 for (xx
= 0, x1
= x0
- glyph
->x
; xx
< glyph
->w
; xx
+= 8) {
1748 for (xx1
= 0; xx1
< 8 && xx
+ xx1
< glyph
->w
; ++xx1
, ++x1
) {
1749 if (state
->clip
->test(x1
, y1
)) {
1750 if (alpha0
& 0x80) {
1767 opClipRes
= clipRes
;
1772 SplashError
Splash::fillImageMask(SplashImageMaskSource src
, void *srcData
,
1773 int w
, int h
, SplashCoord
*mat
,
1777 SplashCoord xScale
, yScale
, xShear
, yShear
, yShear1
;
1778 int tx
, tx2
, ty
, ty2
, scaledWidth
, scaledHeight
, xSign
, ySign
;
1779 int ulx
, uly
, llx
, lly
, urx
, ury
, lrx
, lry
;
1780 int ulx1
, uly1
, llx1
, lly1
, urx1
, ury1
, lrx1
, lry1
;
1781 int xMin
, xMax
, yMin
, yMax
;
1782 SplashClipResult clipRes
, clipRes2
;
1783 int yp
, yq
, yt
, yStep
, lastYStep
;
1784 int xp
, xq
, xt
, xStep
, xSrc
;
1785 int k1
, spanXMin
, spanXMax
, spanY
;
1786 SplashColorPtr pixBuf
, p
;
1788 int x
, y
, x1
, x2
, y2
;
1793 printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
1794 w
, h
, (double)mat
[0], (double)mat
[1], (double)mat
[2],
1795 (double)mat
[3], (double)mat
[4], (double)mat
[5]);
1798 // check for singular matrix
1799 if (splashAbs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.000001) {
1800 return splashErrSingularMatrix
;
1803 // compute scale, shear, rotation, translation parameters
1804 rot
= splashAbs(mat
[1]) > splashAbs(mat
[0]);
1807 yScale
= mat
[2] - (mat
[0] * mat
[3]) / mat
[1];
1808 xShear
= -mat
[3] / yScale
;
1809 yShear
= -mat
[0] / mat
[1];
1812 yScale
= mat
[3] - (mat
[1] * mat
[2]) / mat
[0];
1813 xShear
= mat
[2] / yScale
;
1814 yShear
= mat
[1] / mat
[0];
1816 // Note 1: The PDF spec says that all pixels whose *centers* lie
1817 // within the region get painted -- but that doesn't seem to match
1818 // up with what Acrobat actually does: it ends up leaving gaps
1819 // between image stripes. So we use the same rule here as for
1820 // fills: any pixel that overlaps the region gets painted.
1821 // Note 2: The "glyphMode" flag is a kludge: it switches back to
1822 // "correct" behavior (matching the spec), for use in rendering Type
1824 // Note 3: The +/-0.01 in these computations is to avoid floating
1825 // point precision problems which can lead to gaps between image
1826 // stripes (it can cause image stripes to overlap, but that's a much
1827 // less visible problem).
1830 tx
= splashRound(mat
[4]);
1831 tx2
= splashRound(mat
[4] + xScale
) - 1;
1833 tx
= splashRound(mat
[4]) - 1;
1834 tx2
= splashRound(mat
[4] + xScale
);
1838 tx
= splashFloor(mat
[4] - 0.01);
1839 tx2
= splashFloor(mat
[4] + xScale
+ 0.01);
1841 tx
= splashFloor(mat
[4] + 0.01);
1842 tx2
= splashFloor(mat
[4] + xScale
- 0.01);
1845 scaledWidth
= abs(tx2
- tx
) + 1;
1848 ty
= splashRound(mat
[5]);
1849 ty2
= splashRound(mat
[5] + yScale
) - 1;
1851 ty
= splashRound(mat
[5]) - 1;
1852 ty2
= splashRound(mat
[5] + yScale
);
1856 ty
= splashFloor(mat
[5] - 0.01);
1857 ty2
= splashFloor(mat
[5] + yScale
+ 0.01);
1859 ty
= splashFloor(mat
[5] + 0.01);
1860 ty2
= splashFloor(mat
[5] + yScale
- 0.01);
1863 scaledHeight
= abs(ty2
- ty
) + 1;
1864 xSign
= (xScale
< 0) ? -1 : 1;
1865 ySign
= (yScale
< 0) ? -1 : 1;
1866 yShear1
= (SplashCoord
)xSign
* yShear
;
1871 urx1
= xSign
* (scaledWidth
- 1);
1872 ury1
= (int)(yShear
* urx1
);
1873 llx1
= splashRound(xShear
* ySign
* (scaledHeight
- 1));
1874 lly1
= ySign
* (scaledHeight
- 1) + (int)(yShear
* llx1
);
1875 lrx1
= xSign
* (scaledWidth
- 1) +
1876 splashRound(xShear
* ySign
* (scaledHeight
- 1));
1877 lry1
= ySign
* (scaledHeight
- 1) + (int)(yShear
* lrx1
);
1879 ulx
= tx
+ uly1
; uly
= ty
- ulx1
;
1880 urx
= tx
+ ury1
; ury
= ty
- urx1
;
1881 llx
= tx
+ lly1
; lly
= ty
- llx1
;
1882 lrx
= tx
+ lry1
; lry
= ty
- lrx1
;
1884 ulx
= tx
+ ulx1
; uly
= ty
+ uly1
;
1885 urx
= tx
+ urx1
; ury
= ty
+ ury1
;
1886 llx
= tx
+ llx1
; lly
= ty
+ lly1
;
1887 lrx
= tx
+ lrx1
; lry
= ty
+ lry1
;
1889 xMin
= (ulx
< urx
) ? (ulx
< llx
) ? (ulx
< lrx
) ? ulx
: lrx
1890 : (llx
< lrx
) ? llx
: lrx
1891 : (urx
< llx
) ? (urx
< lrx
) ? urx
: lrx
1892 : (llx
< lrx
) ? llx
: lrx
;
1893 xMax
= (ulx
> urx
) ? (ulx
> llx
) ? (ulx
> lrx
) ? ulx
: lrx
1894 : (llx
> lrx
) ? llx
: lrx
1895 : (urx
> llx
) ? (urx
> lrx
) ? urx
: lrx
1896 : (llx
> lrx
) ? llx
: lrx
;
1897 yMin
= (uly
< ury
) ? (uly
< lly
) ? (uly
< lry
) ? uly
: lry
1898 : (lly
< lry
) ? lly
: lry
1899 : (ury
< lly
) ? (ury
< lry
) ? ury
: lry
1900 : (lly
< lry
) ? lly
: lry
;
1901 yMax
= (uly
> ury
) ? (uly
> lly
) ? (uly
> lry
) ? uly
: lry
1902 : (lly
> lry
) ? lly
: lry
1903 : (ury
> lly
) ? (ury
> lry
) ? ury
: lry
1904 : (lly
> lry
) ? lly
: lry
;
1905 clipRes
= state
->clip
->testRect(xMin
, yMin
, xMax
, yMax
);
1906 opClipRes
= clipRes
;
1908 // compute Bresenham parameters for x and y scaling
1909 yp
= h
/ scaledHeight
;
1910 yq
= h
% scaledHeight
;
1911 xp
= w
/ scaledWidth
;
1912 xq
= w
% scaledWidth
;
1914 // allocate pixel buffer
1915 pixBuf
= (SplashColorPtr
)gmalloc((yp
+ 1) * w
);
1917 // initialize the pixel pipe
1918 pipeInit(&pipe
, 0, 0, state
->fillPattern
, NULL
, state
->fillAlpha
,
1920 if (vectorAntialias
) {
1924 // init y scale Bresenham
1928 for (y
= 0; y
< scaledHeight
; ++y
) {
1930 // y scale Bresenham
1933 if (yt
>= scaledHeight
) {
1938 // read row(s) from image
1939 n
= (yp
> 0) ? yStep
: lastYStep
;
1942 for (i
= 0; i
< n
; ++i
) {
1949 // loop-invariant constants
1950 k1
= splashRound(xShear
* ySign
* y
);
1953 if (clipRes
!= splashClipAllInside
&&
1955 (int)(yShear
* k1
) ==
1956 (int)(yShear
* (xSign
* (scaledWidth
- 1) + k1
))) {
1959 spanXMax
= spanXMin
+ (scaledWidth
- 1);
1962 spanXMin
= spanXMax
- (scaledWidth
- 1);
1964 spanY
= ty
+ ySign
* y
+ (int)(yShear
* k1
);
1965 clipRes2
= state
->clip
->testSpan(spanXMin
, spanXMax
, spanY
);
1966 if (clipRes2
== splashClipAllOutside
) {
1973 // init x scale Bresenham
1981 y1
= (SplashCoord
)ySign
* y
+ yShear
* x1
;
1982 // this is a kludge: if yShear1 is negative, then (int)y1 would
1983 // change immediately after the first pixel, which is not what we
1989 // loop-invariant constants
1990 n
= yStep
> 0 ? yStep
: 1;
1992 for (x
= 0; x
< scaledWidth
; ++x
) {
1994 // x scale Bresenham
1997 if (xt
>= scaledWidth
) {
2011 // compute the alpha value for (x,y) after the x and y scaling
2013 m
= xStep
> 0 ? xStep
: 1;
2016 for (i
= 0; i
< n
; ++i
) {
2017 for (j
= 0; j
< m
; ++j
) {
2023 // blend fill color with background
2025 pipe
.shape
= (pixAcc
== n
* m
)
2027 : (SplashCoord
)pixAcc
/ (SplashCoord
)(n
* m
);
2028 if (vectorAntialias
&& clipRes2
!= splashClipAllInside
) {
2029 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2031 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
, clipRes2
== splashClipAllInside
);
2035 // x scale Bresenham
2052 SplashError
Splash::drawImage(SplashImageSource src
, void *srcData
,
2053 SplashColorMode srcMode
, GBool srcAlpha
,
2054 int w
, int h
, SplashCoord
*mat
) {
2057 SplashCoord xScale
, yScale
, xShear
, yShear
, yShear1
;
2058 int tx
, tx2
, ty
, ty2
, scaledWidth
, scaledHeight
, xSign
, ySign
;
2059 int ulx
, uly
, llx
, lly
, urx
, ury
, lrx
, lry
;
2060 int ulx1
, uly1
, llx1
, lly1
, urx1
, ury1
, lrx1
, lry1
;
2061 int xMin
, xMax
, yMin
, yMax
;
2062 SplashClipResult clipRes
, clipRes2
;
2063 int yp
, yq
, yt
, yStep
, lastYStep
;
2064 int xp
, xq
, xt
, xStep
, xSrc
;
2065 int k1
, spanXMin
, spanXMax
, spanY
;
2066 SplashColorPtr colorBuf
, p
;
2068 Guchar
*alphaBuf
, *q
;
2070 int pixAcc0
, pixAcc1
, pixAcc2
, pixAcc3
;
2072 int pixAcc0
, pixAcc1
, pixAcc2
;
2075 SplashCoord pixMul
, alphaMul
, alpha
;
2076 int x
, y
, x1
, x2
, y2
;
2078 int nComps
, n
, m
, i
, j
;
2081 printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2082 srcMode
, srcAlpha
, w
, h
, (double)mat
[0], (double)mat
[1], (double)mat
[2],
2083 (double)mat
[3], (double)mat
[4], (double)mat
[5]);
2086 // check color modes
2087 ok
= gFalse
; // make gcc happy
2088 nComps
= 0; // make gcc happy
2089 switch (bitmap
->mode
) {
2090 case splashModeMono1
:
2091 case splashModeMono8
:
2092 ok
= srcMode
== splashModeMono8
;
2095 case splashModeRGB8
:
2096 ok
= srcMode
== splashModeRGB8
;
2099 case splashModeBGR8
:
2100 ok
= srcMode
== splashModeBGR8
;
2104 case splashModeCMYK8
:
2105 ok
= srcMode
== splashModeCMYK8
;
2111 return splashErrModeMismatch
;
2114 // check for singular matrix
2115 if (splashAbs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.000001) {
2116 return splashErrSingularMatrix
;
2119 // compute scale, shear, rotation, translation parameters
2120 rot
= splashAbs(mat
[1]) > splashAbs(mat
[0]);
2123 yScale
= mat
[2] - (mat
[0] * mat
[3]) / mat
[1];
2124 xShear
= -mat
[3] / yScale
;
2125 yShear
= -mat
[0] / mat
[1];
2128 yScale
= mat
[3] - (mat
[1] * mat
[2]) / mat
[0];
2129 xShear
= mat
[2] / yScale
;
2130 yShear
= mat
[1] / mat
[0];
2132 // Note 1: The PDF spec says that all pixels whose *centers* lie
2133 // within the region get painted -- but that doesn't seem to match
2134 // up with what Acrobat actually does: it ends up leaving gaps
2135 // between image stripes. So we use the same rule here as for
2136 // fills: any pixel that overlaps the region gets painted.
2137 // Note 2: The +/-0.01 in these computations is to avoid floating
2138 // point precision problems which can lead to gaps between image
2139 // stripes (it can cause image stripes to overlap, but that's a much
2140 // less visible problem).
2142 tx
= splashFloor(mat
[4] - 0.01);
2143 tx2
= splashFloor(mat
[4] + xScale
+ 0.01);
2145 tx
= splashFloor(mat
[4] + 0.01);
2146 tx2
= splashFloor(mat
[4] + xScale
- 0.01);
2148 scaledWidth
= abs(tx2
- tx
) + 1;
2150 ty
= splashFloor(mat
[5] - 0.01);
2151 ty2
= splashFloor(mat
[5] + yScale
+ 0.01);
2153 ty
= splashFloor(mat
[5] + 0.01);
2154 ty2
= splashFloor(mat
[5] + yScale
- 0.01);
2156 scaledHeight
= abs(ty2
- ty
) + 1;
2157 xSign
= (xScale
< 0) ? -1 : 1;
2158 ySign
= (yScale
< 0) ? -1 : 1;
2159 yShear1
= (SplashCoord
)xSign
* yShear
;
2164 urx1
= xSign
* (scaledWidth
- 1);
2165 ury1
= (int)(yShear
* urx1
);
2166 llx1
= splashRound(xShear
* ySign
* (scaledHeight
- 1));
2167 lly1
= ySign
* (scaledHeight
- 1) + (int)(yShear
* llx1
);
2168 lrx1
= xSign
* (scaledWidth
- 1) +
2169 splashRound(xShear
* ySign
* (scaledHeight
- 1));
2170 lry1
= ySign
* (scaledHeight
- 1) + (int)(yShear
* lrx1
);
2172 ulx
= tx
+ uly1
; uly
= ty
- ulx1
;
2173 urx
= tx
+ ury1
; ury
= ty
- urx1
;
2174 llx
= tx
+ lly1
; lly
= ty
- llx1
;
2175 lrx
= tx
+ lry1
; lry
= ty
- lrx1
;
2177 ulx
= tx
+ ulx1
; uly
= ty
+ uly1
;
2178 urx
= tx
+ urx1
; ury
= ty
+ ury1
;
2179 llx
= tx
+ llx1
; lly
= ty
+ lly1
;
2180 lrx
= tx
+ lrx1
; lry
= ty
+ lry1
;
2182 xMin
= (ulx
< urx
) ? (ulx
< llx
) ? (ulx
< lrx
) ? ulx
: lrx
2183 : (llx
< lrx
) ? llx
: lrx
2184 : (urx
< llx
) ? (urx
< lrx
) ? urx
: lrx
2185 : (llx
< lrx
) ? llx
: lrx
;
2186 xMax
= (ulx
> urx
) ? (ulx
> llx
) ? (ulx
> lrx
) ? ulx
: lrx
2187 : (llx
> lrx
) ? llx
: lrx
2188 : (urx
> llx
) ? (urx
> lrx
) ? urx
: lrx
2189 : (llx
> lrx
) ? llx
: lrx
;
2190 yMin
= (uly
< ury
) ? (uly
< lly
) ? (uly
< lry
) ? uly
: lry
2191 : (lly
< lry
) ? lly
: lry
2192 : (ury
< lly
) ? (ury
< lry
) ? ury
: lry
2193 : (lly
< lry
) ? lly
: lry
;
2194 yMax
= (uly
> ury
) ? (uly
> lly
) ? (uly
> lry
) ? uly
: lry
2195 : (lly
> lry
) ? lly
: lry
2196 : (ury
> lly
) ? (ury
> lry
) ? ury
: lry
2197 : (lly
> lry
) ? lly
: lry
;
2198 clipRes
= state
->clip
->testRect(xMin
, yMin
, xMax
, yMax
);
2199 opClipRes
= clipRes
;
2200 if (clipRes
== splashClipAllOutside
) {
2204 // compute Bresenham parameters for x and y scaling
2205 yp
= h
/ scaledHeight
;
2206 yq
= h
% scaledHeight
;
2207 xp
= w
/ scaledWidth
;
2208 xq
= w
% scaledWidth
;
2210 // allocate pixel buffers
2211 colorBuf
= (SplashColorPtr
)gmalloc((yp
+ 1) * w
* nComps
);
2213 alphaBuf
= (Guchar
*)gmalloc((yp
+ 1) * w
);
2218 pixAcc0
= pixAcc1
= pixAcc2
= 0; // make gcc happy
2220 pixAcc3
= 0; // make gcc happy
2223 // initialize the pixel pipe
2224 pipeInit(&pipe
, 0, 0, NULL
, pix
, state
->fillAlpha
,
2225 srcAlpha
|| (vectorAntialias
&& clipRes
!= splashClipAllInside
),
2227 if (vectorAntialias
) {
2233 // init y scale Bresenham
2237 for (y
= 0; y
< scaledHeight
; ++y
) {
2239 // y scale Bresenham
2242 if (yt
>= scaledHeight
) {
2247 // read row(s) from image
2248 n
= (yp
> 0) ? yStep
: lastYStep
;
2252 for (i
= 0; i
< n
; ++i
) {
2253 (*src
)(srcData
, p
, q
);
2260 // loop-invariant constants
2261 k1
= splashRound(xShear
* ySign
* y
);
2264 if (clipRes
!= splashClipAllInside
&&
2266 (int)(yShear
* k1
) ==
2267 (int)(yShear
* (xSign
* (scaledWidth
- 1) + k1
))) {
2270 spanXMax
= spanXMin
+ (scaledWidth
- 1);
2273 spanXMin
= spanXMax
- (scaledWidth
- 1);
2275 spanY
= ty
+ ySign
* y
+ (int)(yShear
* k1
);
2276 clipRes2
= state
->clip
->testSpan(spanXMin
, spanXMax
, spanY
);
2277 if (clipRes2
== splashClipAllOutside
) {
2284 // init x scale Bresenham
2292 y1
= (SplashCoord
)ySign
* y
+ yShear
* x1
;
2293 // this is a kludge: if yShear1 is negative, then (int)y1 would
2294 // change immediately after the first pixel, which is not what
2300 // loop-invariant constants
2301 n
= yStep
> 0 ? yStep
: 1;
2305 case splashModeMono1
:
2306 case splashModeMono8
:
2307 for (x
= 0; x
< scaledWidth
; ++x
) {
2309 // x scale Bresenham
2312 if (xt
>= scaledWidth
) {
2326 // compute the filtered pixel at (x,y) after the x and y scaling
2328 m
= xStep
> 0 ? xStep
: 1;
2330 p
= colorBuf
+ xSrc
;
2331 q
= alphaBuf
+ xSrc
;
2333 for (i
= 0; i
< n
; ++i
) {
2334 for (j
= 0; j
< m
; ++j
) {
2341 pixMul
= (SplashCoord
)1 / (SplashCoord
)(n
* m
);
2342 alphaMul
= pixMul
* (1.0 / 255.0);
2343 alpha
= (SplashCoord
)alphaAcc
* alphaMul
;
2346 pix
[0] = (int)((SplashCoord
)pixAcc0
* pixMul
);
2350 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
2351 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2353 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
,
2354 clipRes2
== splashClipAllInside
);
2358 // x scale Bresenham
2369 case splashModeRGB8
:
2370 case splashModeBGR8
:
2371 for (x
= 0; x
< scaledWidth
; ++x
) {
2373 // x scale Bresenham
2376 if (xt
>= scaledWidth
) {
2390 // compute the filtered pixel at (x,y) after the x and y scaling
2392 m
= xStep
> 0 ? xStep
: 1;
2394 p
= colorBuf
+ xSrc
* 3;
2395 q
= alphaBuf
+ xSrc
;
2396 pixAcc0
= pixAcc1
= pixAcc2
= 0;
2397 for (i
= 0; i
< n
; ++i
) {
2398 for (j
= 0; j
< m
; ++j
) {
2407 pixMul
= (SplashCoord
)1 / (SplashCoord
)(n
* m
);
2408 alphaMul
= pixMul
* (1.0 / 255.0);
2409 alpha
= (SplashCoord
)alphaAcc
* alphaMul
;
2412 pix
[0] = (int)((SplashCoord
)pixAcc0
* pixMul
);
2413 pix
[1] = (int)((SplashCoord
)pixAcc1
* pixMul
);
2414 pix
[2] = (int)((SplashCoord
)pixAcc2
* pixMul
);
2418 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
2419 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2421 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
,
2422 clipRes2
== splashClipAllInside
);
2426 // x scale Bresenham
2438 case splashModeCMYK8
:
2439 for (x
= 0; x
< scaledWidth
; ++x
) {
2441 // x scale Bresenham
2444 if (xt
>= scaledWidth
) {
2458 // compute the filtered pixel at (x,y) after the x and y scaling
2460 m
= xStep
> 0 ? xStep
: 1;
2462 p
= colorBuf
+ xSrc
* 4;
2463 q
= alphaBuf
+ xSrc
;
2464 pixAcc0
= pixAcc1
= pixAcc2
= pixAcc3
= 0;
2465 for (i
= 0; i
< n
; ++i
) {
2466 for (j
= 0; j
< m
; ++j
) {
2476 pixMul
= (SplashCoord
)1 / (SplashCoord
)(n
* m
);
2477 alphaMul
= pixMul
* (1.0 / 255.0);
2478 alpha
= (SplashCoord
)alphaAcc
* alphaMul
;
2481 pix
[0] = (int)((SplashCoord
)pixAcc0
* pixMul
);
2482 pix
[1] = (int)((SplashCoord
)pixAcc1
* pixMul
);
2483 pix
[2] = (int)((SplashCoord
)pixAcc2
* pixMul
);
2484 pix
[3] = (int)((SplashCoord
)pixAcc3
* pixMul
);
2488 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
2489 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2491 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
,
2492 clipRes2
== splashClipAllInside
);
2496 // x scale Bresenham
2506 #endif // SPLASH_CMYK
2512 // init y scale Bresenham
2516 for (y
= 0; y
< scaledHeight
; ++y
) {
2518 // y scale Bresenham
2521 if (yt
>= scaledHeight
) {
2526 // read row(s) from image
2527 n
= (yp
> 0) ? yStep
: lastYStep
;
2530 for (i
= 0; i
< n
; ++i
) {
2531 (*src
)(srcData
, p
, NULL
);
2537 // loop-invariant constants
2538 k1
= splashRound(xShear
* ySign
* y
);
2541 if (clipRes
!= splashClipAllInside
&&
2543 (int)(yShear
* k1
) ==
2544 (int)(yShear
* (xSign
* (scaledWidth
- 1) + k1
))) {
2547 spanXMax
= spanXMin
+ (scaledWidth
- 1);
2550 spanXMin
= spanXMax
- (scaledWidth
- 1);
2552 spanY
= ty
+ ySign
* y
+ (int)(yShear
* k1
);
2553 clipRes2
= state
->clip
->testSpan(spanXMin
, spanXMax
, spanY
);
2554 if (clipRes2
== splashClipAllOutside
) {
2561 // init x scale Bresenham
2569 y1
= (SplashCoord
)ySign
* y
+ yShear
* x1
;
2570 // this is a kludge: if yShear1 is negative, then (int)y1 would
2571 // change immediately after the first pixel, which is not what
2577 // loop-invariant constants
2578 n
= yStep
> 0 ? yStep
: 1;
2582 case splashModeMono1
:
2583 case splashModeMono8
:
2584 for (x
= 0; x
< scaledWidth
; ++x
) {
2586 // x scale Bresenham
2589 if (xt
>= scaledWidth
) {
2603 // compute the filtered pixel at (x,y) after the x and y scaling
2605 m
= xStep
> 0 ? xStep
: 1;
2606 p
= colorBuf
+ xSrc
;
2608 for (i
= 0; i
< n
; ++i
) {
2609 for (j
= 0; j
< m
; ++j
) {
2614 pixMul
= (SplashCoord
)1 / (SplashCoord
)(n
* m
);
2616 pix
[0] = (int)((SplashCoord
)pixAcc0
* pixMul
);
2619 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
2620 pipe
.shape
= (SplashCoord
)1;
2621 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2623 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
,
2624 clipRes2
== splashClipAllInside
);
2627 // x scale Bresenham
2638 case splashModeRGB8
:
2639 case splashModeBGR8
:
2640 for (x
= 0; x
< scaledWidth
; ++x
) {
2642 // x scale Bresenham
2645 if (xt
>= scaledWidth
) {
2659 // compute the filtered pixel at (x,y) after the x and y scaling
2661 m
= xStep
> 0 ? xStep
: 1;
2662 p
= colorBuf
+ xSrc
* 3;
2663 pixAcc0
= pixAcc1
= pixAcc2
= 0;
2664 for (i
= 0; i
< n
; ++i
) {
2665 for (j
= 0; j
< m
; ++j
) {
2672 pixMul
= (SplashCoord
)1 / (SplashCoord
)(n
* m
);
2674 pix
[0] = (int)((SplashCoord
)pixAcc0
* pixMul
);
2675 pix
[1] = (int)((SplashCoord
)pixAcc1
* pixMul
);
2676 pix
[2] = (int)((SplashCoord
)pixAcc2
* pixMul
);
2679 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
2680 pipe
.shape
= (SplashCoord
)1;
2681 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2683 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
,
2684 clipRes2
== splashClipAllInside
);
2687 // x scale Bresenham
2699 case splashModeCMYK8
:
2700 for (x
= 0; x
< scaledWidth
; ++x
) {
2702 // x scale Bresenham
2705 if (xt
>= scaledWidth
) {
2719 // compute the filtered pixel at (x,y) after the x and y scaling
2721 m
= xStep
> 0 ? xStep
: 1;
2722 p
= colorBuf
+ xSrc
* 4;
2723 pixAcc0
= pixAcc1
= pixAcc2
= pixAcc3
= 0;
2724 for (i
= 0; i
< n
; ++i
) {
2725 for (j
= 0; j
< m
; ++j
) {
2733 pixMul
= (SplashCoord
)1 / (SplashCoord
)(n
* m
);
2735 pix
[0] = (int)((SplashCoord
)pixAcc0
* pixMul
);
2736 pix
[1] = (int)((SplashCoord
)pixAcc1
* pixMul
);
2737 pix
[2] = (int)((SplashCoord
)pixAcc2
* pixMul
);
2738 pix
[3] = (int)((SplashCoord
)pixAcc3
* pixMul
);
2741 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
2742 pipe
.shape
= (SplashCoord
)1;
2743 drawAAPixel(&pipe
, tx
+ x2
, ty
+ y2
);
2745 drawPixel(&pipe
, tx
+ x2
, ty
+ y2
,
2746 clipRes2
== splashClipAllInside
);
2749 // x scale Bresenham
2759 #endif // SPLASH_CMYK
2771 SplashError
Splash::composite(SplashBitmap
*src
, int xSrc
, int ySrc
,
2772 int xDest
, int yDest
, int w
, int h
,
2773 GBool noClip
, GBool nonIsolated
) {
2780 if (src
->mode
!= bitmap
->mode
) {
2781 return splashErrModeMismatch
;
2785 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
, state
->fillAlpha
,
2786 gTrue
, nonIsolated
);
2787 for (y
= 0; y
< h
; ++y
) {
2788 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
2789 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
2790 for (x
= 0; x
< w
; ++x
) {
2791 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
2793 if (noClip
|| state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
2794 // this uses shape instead of alpha, which isn't technically
2795 // correct, but works out the same
2796 pipe
.shape
= (SplashCoord
)(alpha
/ 255.0);
2798 updateModX(xDest
+ x
);
2799 updateModY(yDest
+ y
);
2806 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
, state
->fillAlpha
,
2807 gFalse
, nonIsolated
);
2808 for (y
= 0; y
< h
; ++y
) {
2809 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
2810 for (x
= 0; x
< w
; ++x
) {
2811 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
2812 if (noClip
|| state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
2814 updateModX(xDest
+ x
);
2815 updateModY(yDest
+ y
);
2826 void Splash::compositeBackground(SplashColorPtr color
) {
2829 Guchar alpha
, alpha1
, c
, color0
, color1
, color2
, color3
;
2832 switch (bitmap
->mode
) {
2833 case splashModeMono1
:
2835 for (y
= 0; y
< bitmap
->height
; ++y
) {
2836 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
2837 q
= &bitmap
->alpha
[y
* bitmap
->width
];
2839 for (x
= 0; x
< bitmap
->width
; ++x
) {
2841 alpha1
= 255 - alpha
;
2842 c
= (*p
& mask
) ? 0xff : 0x00;
2843 c
= div255(alpha1
* color0
+ alpha
* c
);
2849 if (!(mask
>>= 1)) {
2856 case splashModeMono8
:
2858 for (y
= 0; y
< bitmap
->height
; ++y
) {
2859 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
2860 q
= &bitmap
->alpha
[y
* bitmap
->width
];
2861 for (x
= 0; x
< bitmap
->width
; ++x
) {
2863 alpha1
= 255 - alpha
;
2864 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
2869 case splashModeRGB8
:
2870 case splashModeBGR8
:
2874 for (y
= 0; y
< bitmap
->height
; ++y
) {
2875 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
2876 q
= &bitmap
->alpha
[y
* bitmap
->width
];
2877 for (x
= 0; x
< bitmap
->width
; ++x
) {
2879 alpha1
= 255 - alpha
;
2880 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
2881 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
2882 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
2888 case splashModeCMYK8
:
2893 for (y
= 0; y
< bitmap
->height
; ++y
) {
2894 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
2895 q
= &bitmap
->alpha
[y
* bitmap
->width
];
2896 for (x
= 0; x
< bitmap
->width
; ++x
) {
2898 alpha1
= 255 - alpha
;
2899 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
2900 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
2901 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
2902 p
[3] = div255(alpha1
* color3
+ alpha
* p
[3]);
2909 memset(bitmap
->alpha
, 255, bitmap
->width
* bitmap
->height
);
2912 SplashError
Splash::blitTransparent(SplashBitmap
*src
, int xSrc
, int ySrc
,
2913 int xDest
, int yDest
, int w
, int h
) {
2919 if (src
->mode
!= bitmap
->mode
) {
2920 return splashErrModeMismatch
;
2923 switch (bitmap
->mode
) {
2924 case splashModeMono1
:
2925 for (y
= 0; y
< h
; ++y
) {
2926 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ (xDest
>> 3)];
2927 mask
= 0x80 >> (xDest
& 7);
2928 for (x
= 0; x
< w
; ++x
) {
2929 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
2935 if (!(mask
>>= 1)) {
2942 case splashModeMono8
:
2943 for (y
= 0; y
< h
; ++y
) {
2944 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ xDest
];
2945 for (x
= 0; x
< w
; ++x
) {
2946 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
2951 case splashModeRGB8
:
2952 case splashModeBGR8
:
2953 for (y
= 0; y
< h
; ++y
) {
2954 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 3 * xDest
];
2955 for (x
= 0; x
< w
; ++x
) {
2956 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
2964 case splashModeCMYK8
:
2965 for (y
= 0; y
< h
; ++y
) {
2966 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 4 * xDest
];
2967 for (x
= 0; x
< w
; ++x
) {
2968 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
2979 if (bitmap
->alpha
) {
2980 for (y
= 0; y
< h
; ++y
) {
2981 q
= &bitmap
->alpha
[(yDest
+ y
) * bitmap
->width
+ xDest
];
2982 for (x
= 0; x
< w
; ++x
) {
2991 SplashPath
*Splash::makeStrokePath(SplashPath
*path
, GBool flatten
) {
2992 SplashPath
*pathIn
, *pathOut
;
2993 SplashCoord w
, d
, dx
, dy
, wdx
, wdy
, dxNext
, dyNext
, wdxNext
, wdyNext
;
2994 SplashCoord crossprod
, dotprod
, miter
, m
;
2995 GBool first
, last
, closed
;
2996 int subpathStart
, next
, i
;
2997 int left0
, left1
, left2
, right0
, right1
, right2
, join0
, join1
, join2
;
2998 int leftFirst
, rightFirst
, firstPt
;
3001 pathIn
= flattenPath(path
, state
->matrix
, state
->flatness
);
3002 if (state
->lineDashLength
> 0) {
3003 pathOut
= makeDashedPath(pathIn
);
3011 subpathStart
= 0; // make gcc happy
3012 closed
= gFalse
; // make gcc happy
3013 left0
= left1
= right0
= right1
= join0
= join1
= 0; // make gcc happy
3014 leftFirst
= rightFirst
= firstPt
= 0; // make gcc happy
3016 pathOut
= new SplashPath();
3017 w
= state
->lineWidth
;
3019 for (i
= 0; i
< pathIn
->length
- 1; ++i
) {
3020 if (pathIn
->flags
[i
] & splashPathLast
) {
3023 if ((first
= pathIn
->flags
[i
] & splashPathFirst
)) {
3025 closed
= pathIn
->flags
[i
] & splashPathClosed
;
3027 last
= pathIn
->flags
[i
+1] & splashPathLast
;
3029 // compute the deltas for segment (i, i+1)
3030 d
= splashDist(pathIn
->pts
[i
].x
, pathIn
->pts
[i
].y
,
3031 pathIn
->pts
[i
+1].x
, pathIn
->pts
[i
+1].y
);
3033 // we need to draw end caps on zero-length lines
3034 //~ not clear what the behavior should be for splashLineCapButt
3039 d
= (SplashCoord
)1 / d
;
3040 dx
= d
* (pathIn
->pts
[i
+1].x
- pathIn
->pts
[i
].x
);
3041 dy
= d
* (pathIn
->pts
[i
+1].y
- pathIn
->pts
[i
].y
);
3043 wdx
= (SplashCoord
)0.5 * w
* dx
;
3044 wdy
= (SplashCoord
)0.5 * w
* dy
;
3046 // compute the deltas for segment (i+1, next)
3047 next
= last
? subpathStart
+ 1 : i
+ 2;
3048 d
= splashDist(pathIn
->pts
[i
+1].x
, pathIn
->pts
[i
+1].y
,
3049 pathIn
->pts
[next
].x
, pathIn
->pts
[next
].y
);
3051 // we need to draw end caps on zero-length lines
3052 //~ not clear what the behavior should be for splashLineCapButt
3057 d
= (SplashCoord
)1 / d
;
3058 dxNext
= d
* (pathIn
->pts
[next
].x
- pathIn
->pts
[i
+1].x
);
3059 dyNext
= d
* (pathIn
->pts
[next
].y
- pathIn
->pts
[i
+1].y
);
3061 wdxNext
= (SplashCoord
)0.5 * w
* dxNext
;
3062 wdyNext
= (SplashCoord
)0.5 * w
* dyNext
;
3064 // draw the start cap
3065 pathOut
->moveTo(pathIn
->pts
[i
].x
- wdy
, pathIn
->pts
[i
].y
+ wdx
);
3066 if (i
== subpathStart
) {
3067 firstPt
= pathOut
->length
- 1;
3069 if (first
&& !closed
) {
3070 switch (state
->lineCap
) {
3071 case splashLineCapButt
:
3072 pathOut
->lineTo(pathIn
->pts
[i
].x
+ wdy
, pathIn
->pts
[i
].y
- wdx
);
3074 case splashLineCapRound
:
3075 pathOut
->curveTo(pathIn
->pts
[i
].x
- wdy
- bezierCircle
* wdx
,
3076 pathIn
->pts
[i
].y
+ wdx
- bezierCircle
* wdy
,
3077 pathIn
->pts
[i
].x
- wdx
- bezierCircle
* wdy
,
3078 pathIn
->pts
[i
].y
- wdy
+ bezierCircle
* wdx
,
3079 pathIn
->pts
[i
].x
- wdx
,
3080 pathIn
->pts
[i
].y
- wdy
);
3081 pathOut
->curveTo(pathIn
->pts
[i
].x
- wdx
+ bezierCircle
* wdy
,
3082 pathIn
->pts
[i
].y
- wdy
- bezierCircle
* wdx
,
3083 pathIn
->pts
[i
].x
+ wdy
- bezierCircle
* wdx
,
3084 pathIn
->pts
[i
].y
- wdx
- bezierCircle
* wdy
,
3085 pathIn
->pts
[i
].x
+ wdy
,
3086 pathIn
->pts
[i
].y
- wdx
);
3088 case splashLineCapProjecting
:
3089 pathOut
->lineTo(pathIn
->pts
[i
].x
- wdx
- wdy
,
3090 pathIn
->pts
[i
].y
+ wdx
- wdy
);
3091 pathOut
->lineTo(pathIn
->pts
[i
].x
- wdx
+ wdy
,
3092 pathIn
->pts
[i
].y
- wdx
- wdy
);
3093 pathOut
->lineTo(pathIn
->pts
[i
].x
+ wdy
,
3094 pathIn
->pts
[i
].y
- wdx
);
3098 pathOut
->lineTo(pathIn
->pts
[i
].x
+ wdy
, pathIn
->pts
[i
].y
- wdx
);
3101 // draw the left side of the segment rectangle
3102 left2
= pathOut
->length
- 1;
3103 pathOut
->lineTo(pathIn
->pts
[i
+1].x
+ wdy
, pathIn
->pts
[i
+1].y
- wdx
);
3106 if (last
&& !closed
) {
3107 switch (state
->lineCap
) {
3108 case splashLineCapButt
:
3109 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
, pathIn
->pts
[i
+1].y
+ wdx
);
3111 case splashLineCapRound
:
3112 pathOut
->curveTo(pathIn
->pts
[i
+1].x
+ wdy
+ bezierCircle
* wdx
,
3113 pathIn
->pts
[i
+1].y
- wdx
+ bezierCircle
* wdy
,
3114 pathIn
->pts
[i
+1].x
+ wdx
+ bezierCircle
* wdy
,
3115 pathIn
->pts
[i
+1].y
+ wdy
- bezierCircle
* wdx
,
3116 pathIn
->pts
[i
+1].x
+ wdx
,
3117 pathIn
->pts
[i
+1].y
+ wdy
);
3118 pathOut
->curveTo(pathIn
->pts
[i
+1].x
+ wdx
- bezierCircle
* wdy
,
3119 pathIn
->pts
[i
+1].y
+ wdy
+ bezierCircle
* wdx
,
3120 pathIn
->pts
[i
+1].x
- wdy
+ bezierCircle
* wdx
,
3121 pathIn
->pts
[i
+1].y
+ wdx
+ bezierCircle
* wdy
,
3122 pathIn
->pts
[i
+1].x
- wdy
,
3123 pathIn
->pts
[i
+1].y
+ wdx
);
3125 case splashLineCapProjecting
:
3126 pathOut
->lineTo(pathIn
->pts
[i
+1].x
+ wdy
+ wdx
,
3127 pathIn
->pts
[i
+1].y
- wdx
+ wdy
);
3128 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
+ wdx
,
3129 pathIn
->pts
[i
+1].y
+ wdx
+ wdy
);
3130 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
,
3131 pathIn
->pts
[i
+1].y
+ wdx
);
3135 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
, pathIn
->pts
[i
+1].y
+ wdx
);
3138 // draw the right side of the segment rectangle
3139 right2
= pathOut
->length
- 1;
3143 join2
= pathOut
->length
;
3144 if (!last
|| closed
) {
3145 crossprod
= dx
* dyNext
- dy
* dxNext
;
3146 dotprod
= -(dx
* dxNext
+ dy
* dyNext
);
3147 if (dotprod
> 0.99999) {
3148 // avoid a divide-by-zero -- set miter to something arbitrary
3149 // such that sqrt(miter) will exceed miterLimit (and m is never
3150 // used in that situation)
3151 miter
= (state
->miterLimit
+ 1) * (state
->miterLimit
+ 1);
3154 miter
= (SplashCoord
)2 / ((SplashCoord
)1 - dotprod
);
3156 // this can happen because of floating point inaccuracies
3159 m
= splashSqrt(miter
- 1);
3163 if (state
->lineJoin
== splashLineJoinRound
) {
3164 pathOut
->moveTo(pathIn
->pts
[i
+1].x
+ (SplashCoord
)0.5 * w
,
3165 pathIn
->pts
[i
+1].y
);
3166 pathOut
->curveTo(pathIn
->pts
[i
+1].x
+ (SplashCoord
)0.5 * w
,
3167 pathIn
->pts
[i
+1].y
+ bezierCircle2
* w
,
3168 pathIn
->pts
[i
+1].x
+ bezierCircle2
* w
,
3169 pathIn
->pts
[i
+1].y
+ (SplashCoord
)0.5 * w
,
3171 pathIn
->pts
[i
+1].y
+ (SplashCoord
)0.5 * w
);
3172 pathOut
->curveTo(pathIn
->pts
[i
+1].x
- bezierCircle2
* w
,
3173 pathIn
->pts
[i
+1].y
+ (SplashCoord
)0.5 * w
,
3174 pathIn
->pts
[i
+1].x
- (SplashCoord
)0.5 * w
,
3175 pathIn
->pts
[i
+1].y
+ bezierCircle2
* w
,
3176 pathIn
->pts
[i
+1].x
- (SplashCoord
)0.5 * w
,
3177 pathIn
->pts
[i
+1].y
);
3178 pathOut
->curveTo(pathIn
->pts
[i
+1].x
- (SplashCoord
)0.5 * w
,
3179 pathIn
->pts
[i
+1].y
- bezierCircle2
* w
,
3180 pathIn
->pts
[i
+1].x
- bezierCircle2
* w
,
3181 pathIn
->pts
[i
+1].y
- (SplashCoord
)0.5 * w
,
3183 pathIn
->pts
[i
+1].y
- (SplashCoord
)0.5 * w
);
3184 pathOut
->curveTo(pathIn
->pts
[i
+1].x
+ bezierCircle2
* w
,
3185 pathIn
->pts
[i
+1].y
- (SplashCoord
)0.5 * w
,
3186 pathIn
->pts
[i
+1].x
+ (SplashCoord
)0.5 * w
,
3187 pathIn
->pts
[i
+1].y
- bezierCircle2
* w
,
3188 pathIn
->pts
[i
+1].x
+ (SplashCoord
)0.5 * w
,
3189 pathIn
->pts
[i
+1].y
);
3192 pathOut
->moveTo(pathIn
->pts
[i
+1].x
, pathIn
->pts
[i
+1].y
);
3195 if (crossprod
< 0) {
3196 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdyNext
,
3197 pathIn
->pts
[i
+1].y
+ wdxNext
);
3198 // miter join inside limit
3199 if (state
->lineJoin
== splashLineJoinMiter
&&
3200 splashSqrt(miter
) <= state
->miterLimit
) {
3201 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
+ wdx
* m
,
3202 pathIn
->pts
[i
+1].y
+ wdx
+ wdy
* m
);
3203 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
,
3204 pathIn
->pts
[i
+1].y
+ wdx
);
3205 // bevel join or miter join outside limit
3207 pathOut
->lineTo(pathIn
->pts
[i
+1].x
- wdy
, pathIn
->pts
[i
+1].y
+ wdx
);
3212 pathOut
->lineTo(pathIn
->pts
[i
+1].x
+ wdy
,
3213 pathIn
->pts
[i
+1].y
- wdx
);
3214 // miter join inside limit
3215 if (state
->lineJoin
== splashLineJoinMiter
&&
3216 splashSqrt(miter
) <= state
->miterLimit
) {
3217 pathOut
->lineTo(pathIn
->pts
[i
+1].x
+ wdy
+ wdx
* m
,
3218 pathIn
->pts
[i
+1].y
- wdx
+ wdy
* m
);
3219 pathOut
->lineTo(pathIn
->pts
[i
+1].x
+ wdyNext
,
3220 pathIn
->pts
[i
+1].y
- wdxNext
);
3221 // bevel join or miter join outside limit
3223 pathOut
->lineTo(pathIn
->pts
[i
+1].x
+ wdyNext
,
3224 pathIn
->pts
[i
+1].y
- wdxNext
);
3232 // add stroke adjustment hints
3233 if (state
->strokeAdjust
) {
3234 if (i
>= subpathStart
+ 1) {
3235 if (i
>= subpathStart
+ 2) {
3236 pathOut
->addStrokeAdjustHint(left1
, right1
, left0
+ 1, right0
);
3237 pathOut
->addStrokeAdjustHint(left1
, right1
, join0
, left2
);
3239 pathOut
->addStrokeAdjustHint(left1
, right1
, firstPt
, left2
);
3241 pathOut
->addStrokeAdjustHint(left1
, right1
, right2
+ 1, right2
+ 1);
3249 if (i
== subpathStart
) {
3251 rightFirst
= right2
;
3254 if (i
>= subpathStart
+ 2) {
3255 pathOut
->addStrokeAdjustHint(left1
, right1
, left0
+ 1, right0
);
3256 pathOut
->addStrokeAdjustHint(left1
, right1
,
3257 join0
, pathOut
->length
- 1);
3259 pathOut
->addStrokeAdjustHint(left1
, right1
,
3260 firstPt
, pathOut
->length
- 1);
3263 pathOut
->addStrokeAdjustHint(left1
, right1
, firstPt
, leftFirst
);
3264 pathOut
->addStrokeAdjustHint(left1
, right1
,
3265 rightFirst
+ 1, rightFirst
+ 1);
3266 pathOut
->addStrokeAdjustHint(leftFirst
, rightFirst
,
3268 pathOut
->addStrokeAdjustHint(leftFirst
, rightFirst
,
3269 join1
, pathOut
->length
- 1);
3275 if (pathIn
!= path
) {
3282 void Splash::dumpPath(SplashPath
*path
) {
3285 for (i
= 0; i
< path
->length
; ++i
) {
3286 printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
3287 i
, (double)path
->pts
[i
].x
, (double)path
->pts
[i
].y
,
3288 (path
->flags
[i
] & splashPathFirst
) ? " first" : "",
3289 (path
->flags
[i
] & splashPathLast
) ? " last" : "",
3290 (path
->flags
[i
] & splashPathClosed
) ? " closed" : "",
3291 (path
->flags
[i
] & splashPathCurve
) ? " curve" : "");
3295 void Splash::dumpXPath(SplashXPath
*path
) {
3298 for (i
= 0; i
< path
->length
; ++i
) {
3299 printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
3300 i
, (double)path
->segs
[i
].x0
, (double)path
->segs
[i
].y0
,
3301 (double)path
->segs
[i
].x1
, (double)path
->segs
[i
].y1
,
3302 (path
->segs
[i
].flags
& splashXPathFirst
) ? "F" : " ",
3303 (path
->segs
[i
].flags
& splashXPathLast
) ? "L" : " ",
3304 (path
->segs
[i
].flags
& splashXPathEnd0
) ? "0" : " ",
3305 (path
->segs
[i
].flags
& splashXPathEnd1
) ? "1" : " ",
3306 (path
->segs
[i
].flags
& splashXPathHoriz
) ? "H" : " ",
3307 (path
->segs
[i
].flags
& splashXPathVert
) ? "V" : " ",
3308 (path
->segs
[i
].flags
& splashXPathFlip
) ? "P" : " ");