1 //========================================================================
5 //========================================================================
7 //========================================================================
9 // Modified under the Poppler project - http://poppler.freedesktop.org
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
14 // Copyright (C) 2005-2015 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
16 // Copyright (C) 2010-2015 Thomas Freitag <Thomas.Freitag@alfa.de>
17 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
18 // Copyright (C) 2011-2013, 2015 William Bader <williambader@hotmail.com>
19 // Copyright (C) 2012 Markus Trippelsdorf <markus@trippelsdorf.de>
20 // Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
21 // Copyright (C) 2012 Matthias Kramm <kramm@quiss.org>
23 // To see a description of the changes please see the Changelog file that
24 // came with your tarball or type make ChangeLog if you are building from git
26 //========================================================================
30 #ifdef USE_GCC_PRAGMAS
31 #pragma implementation
40 #include "goo/GooLikely.h"
41 #include "goo/GooList.h"
42 #include "poppler/Error.h"
43 #include "SplashErrorCodes.h"
44 #include "SplashMath.h"
45 #include "SplashBitmap.h"
46 #include "SplashState.h"
47 #include "SplashPath.h"
48 #include "SplashXPath.h"
49 #include "SplashXPathScanner.h"
50 #include "SplashPattern.h"
51 #include "SplashScreen.h"
52 #include "SplashFont.h"
53 #include "SplashGlyphBitmap.h"
57 //------------------------------------------------------------------------
59 #define splashAAGamma 1.5
61 // distance of Bezier control point from center for circle approximation
62 // = (4 * (sqrt(2) - 1) / 3) * r
63 #define bezierCircle ((SplashCoord)0.55228475)
64 #define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
66 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
67 static inline Guchar
div255(int x
) {
68 return (Guchar
)((x
+ (x
>> 8) + 0x80) >> 8);
71 // Clip x to lie in [0, 255].
72 static inline Guchar
clip255(int x
) {
73 return x
< 0 ? 0 : x
> 255 ? 255 : x
;
77 inline void Guswap( T
&a
, T
&b
) { T tmp
= a
; a
=b
; b
=tmp
; }
79 // The PDF spec says that all pixels whose *centers* lie within the
80 // image target region get painted, so we want to round n+0.5 down to
81 // n. But this causes problems, e.g., with PDF files that fill a
82 // rectangle with black and then draw an image to the exact same
83 // rectangle, so we instead use the fill scan conversion rule.
84 // However, the correct rule works better for glyphs, so we also
85 // provide that option in fillImageMask.
87 static inline int imgCoordMungeLower(SplashCoord x
) {
88 return splashCeil(x
+ 0.5) - 1;
90 static inline int imgCoordMungeUpper(SplashCoord x
) {
91 return splashCeil(x
+ 0.5) - 1;
94 static inline int imgCoordMungeLower(SplashCoord x
) {
95 return splashFloor(x
);
97 static inline int imgCoordMungeUpper(SplashCoord x
) {
98 return splashFloor(x
) + 1;
100 static inline int imgCoordMungeLowerC(SplashCoord x
, GBool glyphMode
) {
101 return glyphMode
? (splashCeil(x
+ 0.5) - 1) : splashFloor(x
);
103 static inline int imgCoordMungeUpperC(SplashCoord x
, GBool glyphMode
) {
104 return glyphMode
? (splashCeil(x
+ 0.5) - 1) : (splashFloor(x
) + 1);
108 // Used by drawImage and fillImageMask to divide the target
109 // quadrilateral into sections.
110 struct ImageSection
{
111 int y0
, y1
; // actual y range
112 int ia0
, ia1
; // vertex indices for edge A
113 int ib0
, ib1
; // vertex indices for edge A
114 SplashCoord xa0
, ya0
, xa1
, ya1
; // edge A
115 SplashCoord dxdya
; // slope of edge A
116 SplashCoord xb0
, yb0
, xb1
, yb1
; // edge B
117 SplashCoord dxdyb
; // slope of edge B
120 //------------------------------------------------------------------------
122 //------------------------------------------------------------------------
124 #define splashPipeMaxStages 9
131 SplashPattern
*pattern
;
133 // source alpha and color
139 // non-isolated group alpha0
144 Guchar knockoutOpacity
;
147 SplashColorPtr softMaskPtr
;
149 // destination alpha and color
150 SplashColorPtr destColorPtr
;
152 Guchar
*destAlphaPtr
;
157 // result alpha and color
158 GBool noTransparency
;
159 SplashPipeResultColorCtrl resultColorCtrl
;
161 // non-isolated group correction
162 GBool nonIsolatedGroup
;
164 // the "run" function
165 void (Splash::*run
)(SplashPipe
*pipe
);
168 SplashPipeResultColorCtrl
Splash::pipeResultColorNoAlphaBlend
[] = {
169 splashPipeResultColorNoAlphaBlendMono
,
170 splashPipeResultColorNoAlphaBlendMono
,
171 splashPipeResultColorNoAlphaBlendRGB
,
172 splashPipeResultColorNoAlphaBlendRGB
,
173 splashPipeResultColorNoAlphaBlendRGB
176 splashPipeResultColorNoAlphaBlendCMYK
,
177 splashPipeResultColorNoAlphaBlendDeviceN
181 SplashPipeResultColorCtrl
Splash::pipeResultColorAlphaNoBlend
[] = {
182 splashPipeResultColorAlphaNoBlendMono
,
183 splashPipeResultColorAlphaNoBlendMono
,
184 splashPipeResultColorAlphaNoBlendRGB
,
185 splashPipeResultColorAlphaNoBlendRGB
,
186 splashPipeResultColorAlphaNoBlendRGB
189 splashPipeResultColorAlphaNoBlendCMYK
,
190 splashPipeResultColorAlphaNoBlendDeviceN
194 SplashPipeResultColorCtrl
Splash::pipeResultColorAlphaBlend
[] = {
195 splashPipeResultColorAlphaBlendMono
,
196 splashPipeResultColorAlphaBlendMono
,
197 splashPipeResultColorAlphaBlendRGB
,
198 splashPipeResultColorAlphaBlendRGB
,
199 splashPipeResultColorAlphaBlendRGB
202 splashPipeResultColorAlphaBlendCMYK
,
203 splashPipeResultColorAlphaBlendDeviceN
207 //------------------------------------------------------------------------
209 static void blendXor(SplashColorPtr src
, SplashColorPtr dest
,
210 SplashColorPtr blend
, SplashColorMode cm
) {
213 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
214 blend
[i
] = src
[i
] ^ dest
[i
];
218 //------------------------------------------------------------------------
220 //------------------------------------------------------------------------
222 void Splash::clearModRegion() {
223 modXMin
= bitmap
->getWidth();
224 modYMin
= bitmap
->getHeight();
229 inline void Splash::updateModX(int x
) {
238 inline void Splash::updateModY(int y
) {
247 //------------------------------------------------------------------------
249 //------------------------------------------------------------------------
251 inline void Splash::pipeInit(SplashPipe
*pipe
, int x
, int y
,
252 SplashPattern
*pattern
, SplashColorPtr cSrc
,
253 Guchar aInput
, GBool usesShape
,
254 GBool nonIsolatedGroup
,
255 GBool knockout
, Guchar knockoutOpacity
) {
256 pipeSetXY(pipe
, x
, y
);
257 pipe
->pattern
= NULL
;
261 if (pattern
->isStatic()) {
262 pattern
->getColor(x
, y
, pipe
->cSrcVal
);
264 pipe
->pattern
= pattern
;
266 pipe
->cSrc
= pipe
->cSrcVal
;
272 pipe
->aInput
= aInput
;
273 pipe
->usesShape
= usesShape
;
277 pipe
->knockout
= knockout
;
278 pipe
->knockoutOpacity
= knockoutOpacity
;
281 if (aInput
== 255 && !state
->softMask
&& !usesShape
&&
282 !state
->inNonIsolatedGroup
&& !nonIsolatedGroup
) {
283 pipe
->noTransparency
= gTrue
;
285 pipe
->noTransparency
= gFalse
;
289 if (pipe
->noTransparency
) {
290 // the !state->blendFunc case is handled separately in pipeRun
291 pipe
->resultColorCtrl
= pipeResultColorNoAlphaBlend
[bitmap
->mode
];
292 } else if (!state
->blendFunc
) {
293 pipe
->resultColorCtrl
= pipeResultColorAlphaNoBlend
[bitmap
->mode
];
295 pipe
->resultColorCtrl
= pipeResultColorAlphaBlend
[bitmap
->mode
];
298 // non-isolated group correction
299 pipe
->nonIsolatedGroup
= nonIsolatedGroup
;
301 // select the 'run' function
302 pipe
->run
= &Splash::pipeRun
;
303 if (!pipe
->pattern
&& pipe
->noTransparency
&& !state
->blendFunc
) {
304 if (bitmap
->mode
== splashModeMono1
&& !pipe
->destAlphaPtr
) {
305 pipe
->run
= &Splash::pipeRunSimpleMono1
;
306 } else if (bitmap
->mode
== splashModeMono8
&& pipe
->destAlphaPtr
) {
307 pipe
->run
= &Splash::pipeRunSimpleMono8
;
308 } else if (bitmap
->mode
== splashModeRGB8
&& pipe
->destAlphaPtr
) {
309 pipe
->run
= &Splash::pipeRunSimpleRGB8
;
310 } else if (bitmap
->mode
== splashModeXBGR8
&& pipe
->destAlphaPtr
) {
311 pipe
->run
= &Splash::pipeRunSimpleXBGR8
;
312 } else if (bitmap
->mode
== splashModeBGR8
&& pipe
->destAlphaPtr
) {
313 pipe
->run
= &Splash::pipeRunSimpleBGR8
;
315 } else if (bitmap
->mode
== splashModeCMYK8
&& pipe
->destAlphaPtr
) {
316 pipe
->run
= &Splash::pipeRunSimpleCMYK8
;
317 } else if (bitmap
->mode
== splashModeDeviceN8
&& pipe
->destAlphaPtr
) {
318 pipe
->run
= &Splash::pipeRunSimpleDeviceN8
;
321 } else if (!pipe
->pattern
&& !pipe
->noTransparency
&& !state
->softMask
&&
323 !(state
->inNonIsolatedGroup
&& alpha0Bitmap
->alpha
) &&
324 !state
->blendFunc
&& !pipe
->nonIsolatedGroup
) {
325 if (bitmap
->mode
== splashModeMono1
&& !pipe
->destAlphaPtr
) {
326 pipe
->run
= &Splash::pipeRunAAMono1
;
327 } else if (bitmap
->mode
== splashModeMono8
&& pipe
->destAlphaPtr
) {
328 pipe
->run
= &Splash::pipeRunAAMono8
;
329 } else if (bitmap
->mode
== splashModeRGB8
&& pipe
->destAlphaPtr
) {
330 pipe
->run
= &Splash::pipeRunAARGB8
;
331 } else if (bitmap
->mode
== splashModeXBGR8
&& pipe
->destAlphaPtr
) {
332 pipe
->run
= &Splash::pipeRunAAXBGR8
;
333 } else if (bitmap
->mode
== splashModeBGR8
&& pipe
->destAlphaPtr
) {
334 pipe
->run
= &Splash::pipeRunAABGR8
;
336 } else if (bitmap
->mode
== splashModeCMYK8
&& pipe
->destAlphaPtr
) {
337 pipe
->run
= &Splash::pipeRunAACMYK8
;
338 } else if (bitmap
->mode
== splashModeDeviceN8
&& pipe
->destAlphaPtr
) {
339 pipe
->run
= &Splash::pipeRunAADeviceN8
;
346 void Splash::pipeRun(SplashPipe
*pipe
) {
347 Guchar aSrc
, aDest
, alphaI
, alphaIm1
, alpha0
, aResult
;
348 SplashColor cSrcNonIso
, cDest
, cBlend
;
350 Guchar cResult0
, cResult1
, cResult2
, cResult3
;
354 Guchar cResult
[SPOT_NCOMPS
+4];
359 // static pattern: handled in pipeInit
360 // fixed color: handled in pipeInit
364 if (!pipe
->pattern
->getColor(pipe
->x
, pipe
->y
, pipe
->cSrcVal
)) {
369 if (bitmap
->mode
== splashModeCMYK8
|| bitmap
->mode
== splashModeDeviceN8
) {
370 if (state
->fillOverprint
&& state
->overprintMode
&& pipe
->pattern
->isCMYK()) {
372 if (pipe
->cSrcVal
[0] == 0) {
375 if (pipe
->cSrcVal
[1] == 0) {
378 if (pipe
->cSrcVal
[2] == 0) {
381 if (pipe
->cSrcVal
[3] == 0) {
384 state
->overprintMask
= mask
;
390 if (pipe
->noTransparency
&& !state
->blendFunc
) {
392 //----- write destination pixel
394 switch (bitmap
->mode
) {
395 case splashModeMono1
:
396 cResult0
= state
->grayTransfer
[pipe
->cSrc
[0]];
397 if (state
->screen
->test(pipe
->x
, pipe
->y
, cResult0
)) {
398 *pipe
->destColorPtr
|= pipe
->destColorMask
;
400 *pipe
->destColorPtr
&= ~pipe
->destColorMask
;
402 if (!(pipe
->destColorMask
>>= 1)) {
403 pipe
->destColorMask
= 0x80;
404 ++pipe
->destColorPtr
;
407 case splashModeMono8
:
408 *pipe
->destColorPtr
++ = state
->grayTransfer
[pipe
->cSrc
[0]];
411 *pipe
->destColorPtr
++ = state
->rgbTransferR
[pipe
->cSrc
[0]];
412 *pipe
->destColorPtr
++ = state
->rgbTransferG
[pipe
->cSrc
[1]];
413 *pipe
->destColorPtr
++ = state
->rgbTransferB
[pipe
->cSrc
[2]];
415 case splashModeXBGR8
:
416 *pipe
->destColorPtr
++ = state
->rgbTransferB
[pipe
->cSrc
[2]];
417 *pipe
->destColorPtr
++ = state
->rgbTransferG
[pipe
->cSrc
[1]];
418 *pipe
->destColorPtr
++ = state
->rgbTransferR
[pipe
->cSrc
[0]];
419 *pipe
->destColorPtr
++ = 255;
422 *pipe
->destColorPtr
++ = state
->rgbTransferB
[pipe
->cSrc
[2]];
423 *pipe
->destColorPtr
++ = state
->rgbTransferG
[pipe
->cSrc
[1]];
424 *pipe
->destColorPtr
++ = state
->rgbTransferR
[pipe
->cSrc
[0]];
427 case splashModeCMYK8
:
428 if (state
->overprintMask
& 1) {
429 pipe
->destColorPtr
[0] = (state
->overprintAdditive
) ?
430 std::min
<int>(pipe
->destColorPtr
[0] + state
->cmykTransferC
[pipe
->cSrc
[0]], 255) :
431 state
->cmykTransferC
[pipe
->cSrc
[0]];
433 if (state
->overprintMask
& 2) {
434 pipe
->destColorPtr
[1] = (state
->overprintAdditive
) ?
435 std::min
<int>(pipe
->destColorPtr
[1] + state
->cmykTransferM
[pipe
->cSrc
[1]], 255) :
436 state
->cmykTransferM
[pipe
->cSrc
[1]];
438 if (state
->overprintMask
& 4) {
439 pipe
->destColorPtr
[2] = (state
->overprintAdditive
) ?
440 std::min
<int>(pipe
->destColorPtr
[2] + state
->cmykTransferY
[pipe
->cSrc
[2]], 255) :
441 state
->cmykTransferY
[pipe
->cSrc
[2]];
443 if (state
->overprintMask
& 8) {
444 pipe
->destColorPtr
[3] = (state
->overprintAdditive
) ?
445 std::min
<int>(pipe
->destColorPtr
[3] + state
->cmykTransferK
[pipe
->cSrc
[3]], 255) :
446 state
->cmykTransferK
[pipe
->cSrc
[3]];
448 pipe
->destColorPtr
+= 4;
450 case splashModeDeviceN8
:
452 for (cp
= 0; cp
< SPOT_NCOMPS
+ 4; cp
++) {
453 if (state
->overprintMask
& mask
) {
454 pipe
->destColorPtr
[cp
] = state
->deviceNTransfer
[cp
][pipe
->cSrc
[cp
]];
458 pipe
->destColorPtr
+= (SPOT_NCOMPS
+4);
462 if (pipe
->destAlphaPtr
) {
463 *pipe
->destAlphaPtr
++ = 255;
468 //----- read destination pixel
470 Guchar
*destColorPtr
;
471 if (pipe
->shape
&& state
->blendFunc
&& pipe
->knockout
&& alpha0Bitmap
!= NULL
) {
472 destColorPtr
= alpha0Bitmap
->data
+ (alpha0Y
+pipe
->y
)*alpha0Bitmap
->rowSize
;
473 switch (bitmap
->mode
) {
474 case splashModeMono1
:
475 destColorPtr
+= (alpha0X
+pipe
->x
) / 8;
477 case splashModeMono8
:
478 destColorPtr
+= (alpha0X
+pipe
->x
);
482 destColorPtr
+= (alpha0X
+pipe
->x
) * 3;
484 case splashModeXBGR8
:
486 case splashModeCMYK8
:
488 destColorPtr
+= (alpha0X
+pipe
->x
) * 4;
491 case splashModeDeviceN8
:
492 destColorPtr
+= (alpha0X
+pipe
->x
) * (SPOT_NCOMPS
+ 4);
497 destColorPtr
= pipe
->destColorPtr
;
499 switch (bitmap
->mode
) {
500 case splashModeMono1
:
501 cDest
[0] = (*destColorPtr
& pipe
->destColorMask
) ? 0xff : 0x00;
503 case splashModeMono8
:
504 cDest
[0] = *destColorPtr
;
507 cDest
[0] = destColorPtr
[0];
508 cDest
[1] = destColorPtr
[1];
509 cDest
[2] = destColorPtr
[2];
511 case splashModeXBGR8
:
512 cDest
[0] = destColorPtr
[2];
513 cDest
[1] = destColorPtr
[1];
514 cDest
[2] = destColorPtr
[0];
518 cDest
[0] = destColorPtr
[2];
519 cDest
[1] = destColorPtr
[1];
520 cDest
[2] = destColorPtr
[0];
523 case splashModeCMYK8
:
524 cDest
[0] = destColorPtr
[0];
525 cDest
[1] = destColorPtr
[1];
526 cDest
[2] = destColorPtr
[2];
527 cDest
[3] = destColorPtr
[3];
529 case splashModeDeviceN8
:
530 for (cp
= 0; cp
< SPOT_NCOMPS
+ 4; cp
++)
531 cDest
[cp
] = destColorPtr
[cp
];
535 if (pipe
->destAlphaPtr
) {
536 aDest
= *pipe
->destAlphaPtr
;
543 if (state
->softMask
) {
544 if (pipe
->usesShape
) {
545 aSrc
= div255(div255(pipe
->aInput
* *pipe
->softMaskPtr
++) *
548 aSrc
= div255(pipe
->aInput
* *pipe
->softMaskPtr
++);
550 } else if (pipe
->usesShape
) {
551 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
556 //----- non-isolated group correction
558 if (pipe
->nonIsolatedGroup
) {
559 // This path is only used when Splash::composite() is called to
560 // composite a non-isolated group onto the backdrop. In this
561 // case, pipe->shape is the source (group) alpha.
562 if (pipe
->shape
== 0) {
563 // this value will be multiplied by zero later, so it doesn't
564 // matter what we use
567 t
= (aDest
* 255) / pipe
->shape
- aDest
;
568 switch (bitmap
->mode
) {
570 case splashModeDeviceN8
:
571 for (cp
= 0; cp
< SPOT_NCOMPS
+ 4; cp
++)
572 cSrcNonIso
[cp
] = clip255(pipe
->cSrc
[cp
] +
573 ((pipe
->cSrc
[cp
] - cDest
[cp
]) * t
) / 255);
575 case splashModeCMYK8
:
576 for (cp
= 0; cp
< 4; cp
++)
577 cSrcNonIso
[cp
] = clip255(pipe
->cSrc
[cp
] +
578 ((pipe
->cSrc
[cp
] - cDest
[cp
]) * t
) / 255);
581 case splashModeXBGR8
:
585 cSrcNonIso
[2] = clip255(pipe
->cSrc
[2] +
586 ((pipe
->cSrc
[2] - cDest
[2]) * t
) / 255);
587 cSrcNonIso
[1] = clip255(pipe
->cSrc
[1] +
588 ((pipe
->cSrc
[1] - cDest
[1]) * t
) / 255);
589 case splashModeMono1
:
590 case splashModeMono8
:
591 cSrcNonIso
[0] = clip255(pipe
->cSrc
[0] +
592 ((pipe
->cSrc
[0] - cDest
[0]) * t
) / 255);
596 // knockout: remove backdrop color
597 if (pipe
->knockout
&& pipe
->shape
>= pipe
->knockoutOpacity
) {
605 //----- blend function
607 if (state
->blendFunc
) {
609 if (bitmap
->mode
== splashModeDeviceN8
) {
610 for (int k
= 4; k
< 4 + SPOT_NCOMPS
; k
++) {
615 (*state
->blendFunc
)(cSrc
, cDest
, cBlend
, bitmap
->mode
);
618 //----- result alpha and non-isolated group element correction
620 if (pipe
->noTransparency
) {
621 alphaI
= alphaIm1
= aResult
= 255;
623 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
626 // alphaIm1 = alpha_(i-1)
627 if (pipe
->alpha0Ptr
) {
628 alpha0
= *pipe
->alpha0Ptr
++;
629 alphaI
= aResult
+ alpha0
- div255(aResult
* alpha0
);
630 alphaIm1
= alpha0
+ aDest
- div255(alpha0
* aDest
);
639 cResult0
= cResult1
= cResult2
= cResult3
= 0; // make gcc happy
641 switch (pipe
->resultColorCtrl
) {
643 case splashPipeResultColorNoAlphaBlendMono
:
644 cResult0
= state
->grayTransfer
[div255((255 - aDest
) * cSrc
[0] +
647 case splashPipeResultColorNoAlphaBlendRGB
:
648 cResult0
= state
->rgbTransferR
[div255((255 - aDest
) * cSrc
[0] +
650 cResult1
= state
->rgbTransferG
[div255((255 - aDest
) * cSrc
[1] +
652 cResult2
= state
->rgbTransferB
[div255((255 - aDest
) * cSrc
[2] +
656 case splashPipeResultColorNoAlphaBlendCMYK
:
657 cResult0
= state
->cmykTransferC
[div255((255 - aDest
) * cSrc
[0] +
659 cResult1
= state
->cmykTransferM
[div255((255 - aDest
) * cSrc
[1] +
661 cResult2
= state
->cmykTransferY
[div255((255 - aDest
) * cSrc
[2] +
663 cResult3
= state
->cmykTransferK
[div255((255 - aDest
) * cSrc
[3] +
666 case splashPipeResultColorNoAlphaBlendDeviceN
:
667 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
668 cResult
[cp
] = state
->deviceNTransfer
[cp
][div255((255 - aDest
) * cSrc
[cp
] +
669 aDest
* cBlend
[cp
])];
673 case splashPipeResultColorAlphaNoBlendMono
:
677 cResult0
= state
->grayTransfer
[((alphaI
- aSrc
) * cDest
[0] +
678 aSrc
* cSrc
[0]) / alphaI
];
681 case splashPipeResultColorAlphaNoBlendRGB
:
687 cResult0
= state
->rgbTransferR
[((alphaI
- aSrc
) * cDest
[0] +
688 aSrc
* cSrc
[0]) / alphaI
];
689 cResult1
= state
->rgbTransferG
[((alphaI
- aSrc
) * cDest
[1] +
690 aSrc
* cSrc
[1]) / alphaI
];
691 cResult2
= state
->rgbTransferB
[((alphaI
- aSrc
) * cDest
[2] +
692 aSrc
* cSrc
[2]) / alphaI
];
696 case splashPipeResultColorAlphaNoBlendCMYK
:
703 cResult0
= state
->cmykTransferC
[((alphaI
- aSrc
) * cDest
[0] +
704 aSrc
* cSrc
[0]) / alphaI
];
705 cResult1
= state
->cmykTransferM
[((alphaI
- aSrc
) * cDest
[1] +
706 aSrc
* cSrc
[1]) / alphaI
];
707 cResult2
= state
->cmykTransferY
[((alphaI
- aSrc
) * cDest
[2] +
708 aSrc
* cSrc
[2]) / alphaI
];
709 cResult3
= state
->cmykTransferK
[((alphaI
- aSrc
) * cDest
[3] +
710 aSrc
* cSrc
[3]) / alphaI
];
713 case splashPipeResultColorAlphaNoBlendDeviceN
:
715 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
718 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
719 cResult
[cp
] = state
->deviceNTransfer
[cp
][((alphaI
- aSrc
) * cDest
[cp
] +
720 aSrc
* cSrc
[cp
]) / alphaI
];
725 case splashPipeResultColorAlphaBlendMono
:
729 cResult0
= state
->grayTransfer
[((alphaI
- aSrc
) * cDest
[0] +
730 aSrc
* ((255 - alphaIm1
) * cSrc
[0] +
731 alphaIm1
* cBlend
[0]) / 255) /
735 case splashPipeResultColorAlphaBlendRGB
:
741 cResult0
= state
->rgbTransferR
[((alphaI
- aSrc
) * cDest
[0] +
742 aSrc
* ((255 - alphaIm1
) * cSrc
[0] +
743 alphaIm1
* cBlend
[0]) / 255) /
745 cResult1
= state
->rgbTransferG
[((alphaI
- aSrc
) * cDest
[1] +
746 aSrc
* ((255 - alphaIm1
) * cSrc
[1] +
747 alphaIm1
* cBlend
[1]) / 255) /
749 cResult2
= state
->rgbTransferB
[((alphaI
- aSrc
) * cDest
[2] +
750 aSrc
* ((255 - alphaIm1
) * cSrc
[2] +
751 alphaIm1
* cBlend
[2]) / 255) /
756 case splashPipeResultColorAlphaBlendCMYK
:
763 cResult0
= state
->cmykTransferC
[((alphaI
- aSrc
) * cDest
[0] +
764 aSrc
* ((255 - alphaIm1
) * cSrc
[0] +
765 alphaIm1
* cBlend
[0]) / 255) /
767 cResult1
= state
->cmykTransferM
[((alphaI
- aSrc
) * cDest
[1] +
768 aSrc
* ((255 - alphaIm1
) * cSrc
[1] +
769 alphaIm1
* cBlend
[1]) / 255) /
771 cResult2
= state
->cmykTransferY
[((alphaI
- aSrc
) * cDest
[2] +
772 aSrc
* ((255 - alphaIm1
) * cSrc
[2] +
773 alphaIm1
* cBlend
[2]) / 255) /
775 cResult3
= state
->cmykTransferK
[((alphaI
- aSrc
) * cDest
[3] +
776 aSrc
* ((255 - alphaIm1
) * cSrc
[3] +
777 alphaIm1
* cBlend
[3]) / 255) /
781 case splashPipeResultColorAlphaBlendDeviceN
:
783 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
786 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
787 cResult
[cp
] = state
->deviceNTransfer
[cp
][((alphaI
- aSrc
) * cDest
[cp
] +
788 aSrc
* ((255 - alphaIm1
) * cSrc
[cp
] +
789 alphaIm1
* cBlend
[cp
]) / 255) /
796 //----- write destination pixel
798 switch (bitmap
->mode
) {
799 case splashModeMono1
:
800 if (state
->screen
->test(pipe
->x
, pipe
->y
, cResult0
)) {
801 *pipe
->destColorPtr
|= pipe
->destColorMask
;
803 *pipe
->destColorPtr
&= ~pipe
->destColorMask
;
805 if (!(pipe
->destColorMask
>>= 1)) {
806 pipe
->destColorMask
= 0x80;
807 ++pipe
->destColorPtr
;
810 case splashModeMono8
:
811 *pipe
->destColorPtr
++ = cResult0
;
814 *pipe
->destColorPtr
++ = cResult0
;
815 *pipe
->destColorPtr
++ = cResult1
;
816 *pipe
->destColorPtr
++ = cResult2
;
818 case splashModeXBGR8
:
819 *pipe
->destColorPtr
++ = cResult2
;
820 *pipe
->destColorPtr
++ = cResult1
;
821 *pipe
->destColorPtr
++ = cResult0
;
822 *pipe
->destColorPtr
++ = 255;
825 *pipe
->destColorPtr
++ = cResult2
;
826 *pipe
->destColorPtr
++ = cResult1
;
827 *pipe
->destColorPtr
++ = cResult0
;
830 case splashModeCMYK8
:
831 if (state
->overprintMask
& 1) {
832 pipe
->destColorPtr
[0] = (state
->overprintAdditive
) ?
833 std::min
<int>(pipe
->destColorPtr
[0] + cResult0
, 255) :
836 if (state
->overprintMask
& 2) {
837 pipe
->destColorPtr
[1] = (state
->overprintAdditive
) ?
838 std::min
<int>(pipe
->destColorPtr
[1] + cResult1
, 255) :
841 if (state
->overprintMask
& 4) {
842 pipe
->destColorPtr
[2] = (state
->overprintAdditive
) ?
843 std::min
<int>(pipe
->destColorPtr
[2] + cResult2
, 255) :
846 if (state
->overprintMask
& 8) {
847 pipe
->destColorPtr
[3] = (state
->overprintAdditive
) ?
848 std::min
<int>(pipe
->destColorPtr
[3] + cResult3
, 255) :
851 pipe
->destColorPtr
+= 4;
853 case splashModeDeviceN8
:
855 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++) {
856 if (state
->overprintMask
& mask
) {
857 pipe
->destColorPtr
[cp
] = cResult
[cp
];
861 pipe
->destColorPtr
+= (SPOT_NCOMPS
+4);
865 if (pipe
->destAlphaPtr
) {
866 *pipe
->destAlphaPtr
++ = aResult
;
875 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
876 // bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
877 void Splash::pipeRunSimpleMono1(SplashPipe
*pipe
) {
880 //----- write destination pixel
881 cResult0
= state
->grayTransfer
[pipe
->cSrc
[0]];
882 if (state
->screen
->test(pipe
->x
, pipe
->y
, cResult0
)) {
883 *pipe
->destColorPtr
|= pipe
->destColorMask
;
885 *pipe
->destColorPtr
&= ~pipe
->destColorMask
;
887 if (!(pipe
->destColorMask
>>= 1)) {
888 pipe
->destColorMask
= 0x80;
889 ++pipe
->destColorPtr
;
896 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
897 // bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
898 void Splash::pipeRunSimpleMono8(SplashPipe
*pipe
) {
899 //----- write destination pixel
900 *pipe
->destColorPtr
++ = state
->grayTransfer
[pipe
->cSrc
[0]];
901 *pipe
->destAlphaPtr
++ = 255;
907 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
908 // bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
909 void Splash::pipeRunSimpleRGB8(SplashPipe
*pipe
) {
910 //----- write destination pixel
911 *pipe
->destColorPtr
++ = state
->rgbTransferR
[pipe
->cSrc
[0]];
912 *pipe
->destColorPtr
++ = state
->rgbTransferG
[pipe
->cSrc
[1]];
913 *pipe
->destColorPtr
++ = state
->rgbTransferB
[pipe
->cSrc
[2]];
914 *pipe
->destAlphaPtr
++ = 255;
920 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
921 // bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
922 void Splash::pipeRunSimpleXBGR8(SplashPipe
*pipe
) {
923 //----- write destination pixel
924 *pipe
->destColorPtr
++ = state
->rgbTransferB
[pipe
->cSrc
[2]];
925 *pipe
->destColorPtr
++ = state
->rgbTransferG
[pipe
->cSrc
[1]];
926 *pipe
->destColorPtr
++ = state
->rgbTransferR
[pipe
->cSrc
[0]];
927 *pipe
->destColorPtr
++ = 255;
928 *pipe
->destAlphaPtr
++ = 255;
934 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
935 // bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
936 void Splash::pipeRunSimpleBGR8(SplashPipe
*pipe
) {
937 //----- write destination pixel
938 *pipe
->destColorPtr
++ = state
->rgbTransferB
[pipe
->cSrc
[2]];
939 *pipe
->destColorPtr
++ = state
->rgbTransferG
[pipe
->cSrc
[1]];
940 *pipe
->destColorPtr
++ = state
->rgbTransferR
[pipe
->cSrc
[0]];
941 *pipe
->destAlphaPtr
++ = 255;
948 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
949 // bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
950 void Splash::pipeRunSimpleCMYK8(SplashPipe
*pipe
) {
951 //----- write destination pixel
952 if (state
->overprintMask
& 1) {
953 pipe
->destColorPtr
[0] = (state
->overprintAdditive
) ?
954 std::min
<int>(pipe
->destColorPtr
[0] + state
->cmykTransferC
[pipe
->cSrc
[0]], 255) :
955 state
->cmykTransferC
[pipe
->cSrc
[0]];
957 if (state
->overprintMask
& 2) {
958 pipe
->destColorPtr
[1] = (state
->overprintAdditive
) ?
959 std::min
<int>(pipe
->destColorPtr
[1] + state
->cmykTransferM
[pipe
->cSrc
[1]], 255) :
960 state
->cmykTransferM
[pipe
->cSrc
[1]];
962 if (state
->overprintMask
& 4) {
963 pipe
->destColorPtr
[2] = (state
->overprintAdditive
) ?
964 std::min
<int>(pipe
->destColorPtr
[2] + state
->cmykTransferY
[pipe
->cSrc
[2]], 255) :
965 state
->cmykTransferY
[pipe
->cSrc
[2]];
967 if (state
->overprintMask
& 8) {
968 pipe
->destColorPtr
[3] = (state
->overprintAdditive
) ?
969 std::min
<int>(pipe
->destColorPtr
[3] + state
->cmykTransferK
[pipe
->cSrc
[3]], 255) :
970 state
->cmykTransferK
[pipe
->cSrc
[3]];
972 pipe
->destColorPtr
+= 4;
973 *pipe
->destAlphaPtr
++ = 255;
979 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
980 // bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
981 void Splash::pipeRunSimpleDeviceN8(SplashPipe
*pipe
) {
982 //----- write destination pixel
984 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++) {
985 if (state
->overprintMask
& mask
) {
986 pipe
->destColorPtr
[cp
] = state
->deviceNTransfer
[cp
][pipe
->cSrc
[cp
]];
990 pipe
->destColorPtr
+= (SPOT_NCOMPS
+4);
991 *pipe
->destAlphaPtr
++ = 255;
998 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
999 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1000 // !pipe->nonIsolatedGroup &&
1001 // bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr
1002 void Splash::pipeRunAAMono1(SplashPipe
*pipe
) {
1007 //----- read destination pixel
1008 cDest
[0] = (*pipe
->destColorPtr
& pipe
->destColorMask
) ? 0xff : 0x00;
1010 //----- source alpha
1011 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1013 //----- result color
1014 // note: aDest = alpha2 = aResult = 0xff
1015 cResult0
= state
->grayTransfer
[(Guchar
)div255((0xff - aSrc
) * cDest
[0] +
1016 aSrc
* pipe
->cSrc
[0])];
1018 //----- write destination pixel
1019 if (state
->screen
->test(pipe
->x
, pipe
->y
, cResult0
)) {
1020 *pipe
->destColorPtr
|= pipe
->destColorMask
;
1022 *pipe
->destColorPtr
&= ~pipe
->destColorMask
;
1024 if (!(pipe
->destColorMask
>>= 1)) {
1025 pipe
->destColorMask
= 0x80;
1026 ++pipe
->destColorPtr
;
1033 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1034 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1035 // !pipe->nonIsolatedGroup &&
1036 // bitmap->mode == splashModeMono8 && pipe->destAlphaPtr
1037 void Splash::pipeRunAAMono8(SplashPipe
*pipe
) {
1038 Guchar aSrc
, aDest
, alpha2
, aResult
;
1042 //----- read destination pixel
1043 cDest
[0] = *pipe
->destColorPtr
;
1044 aDest
= *pipe
->destAlphaPtr
;
1046 //----- source alpha
1047 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1049 //----- result alpha and non-isolated group element correction
1050 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
1053 //----- result color
1057 cResult0
= state
->grayTransfer
[(Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
1058 aSrc
* pipe
->cSrc
[0]) / alpha2
)];
1061 //----- write destination pixel
1062 *pipe
->destColorPtr
++ = cResult0
;
1063 *pipe
->destAlphaPtr
++ = aResult
;
1069 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1070 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1071 // !pipe->nonIsolatedGroup &&
1072 // bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr
1073 void Splash::pipeRunAARGB8(SplashPipe
*pipe
) {
1074 Guchar aSrc
, aDest
, alpha2
, aResult
;
1076 Guchar cResult0
, cResult1
, cResult2
;
1078 //----- read destination pixel
1079 cDest
[0] = pipe
->destColorPtr
[0];
1080 cDest
[1] = pipe
->destColorPtr
[1];
1081 cDest
[2] = pipe
->destColorPtr
[2];
1082 aDest
= *pipe
->destAlphaPtr
;
1084 //----- source alpha
1085 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1087 //----- result alpha and non-isolated group element correction
1088 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
1091 //----- result color
1097 cResult0
= state
->rgbTransferR
[(Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
1098 aSrc
* pipe
->cSrc
[0]) / alpha2
)];
1099 cResult1
= state
->rgbTransferG
[(Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
1100 aSrc
* pipe
->cSrc
[1]) / alpha2
)];
1101 cResult2
= state
->rgbTransferB
[(Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
1102 aSrc
* pipe
->cSrc
[2]) / alpha2
)];
1105 //----- write destination pixel
1106 *pipe
->destColorPtr
++ = cResult0
;
1107 *pipe
->destColorPtr
++ = cResult1
;
1108 *pipe
->destColorPtr
++ = cResult2
;
1109 *pipe
->destAlphaPtr
++ = aResult
;
1115 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1116 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1117 // !pipe->nonIsolatedGroup &&
1118 // bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr
1119 void Splash::pipeRunAAXBGR8(SplashPipe
*pipe
) {
1120 Guchar aSrc
, aDest
, alpha2
, aResult
;
1122 Guchar cResult0
, cResult1
, cResult2
;
1124 //----- read destination pixel
1125 cDest
[0] = pipe
->destColorPtr
[2];
1126 cDest
[1] = pipe
->destColorPtr
[1];
1127 cDest
[2] = pipe
->destColorPtr
[0];
1128 aDest
= *pipe
->destAlphaPtr
;
1130 //----- source alpha
1131 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1133 //----- result alpha and non-isolated group element correction
1134 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
1137 //----- result color
1143 cResult0
= state
->rgbTransferR
[(Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
1144 aSrc
* pipe
->cSrc
[0]) / alpha2
)];
1145 cResult1
= state
->rgbTransferG
[(Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
1146 aSrc
* pipe
->cSrc
[1]) / alpha2
)];
1147 cResult2
= state
->rgbTransferB
[(Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
1148 aSrc
* pipe
->cSrc
[2]) / alpha2
)];
1151 //----- write destination pixel
1152 *pipe
->destColorPtr
++ = cResult2
;
1153 *pipe
->destColorPtr
++ = cResult1
;
1154 *pipe
->destColorPtr
++ = cResult0
;
1155 *pipe
->destColorPtr
++ = 255;
1156 *pipe
->destAlphaPtr
++ = aResult
;
1162 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1163 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1164 // !pipe->nonIsolatedGroup &&
1165 // bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr
1166 void Splash::pipeRunAABGR8(SplashPipe
*pipe
) {
1167 Guchar aSrc
, aDest
, alpha2
, aResult
;
1169 Guchar cResult0
, cResult1
, cResult2
;
1171 //----- read destination pixel
1172 cDest
[0] = pipe
->destColorPtr
[2];
1173 cDest
[1] = pipe
->destColorPtr
[1];
1174 cDest
[2] = pipe
->destColorPtr
[0];
1175 aDest
= *pipe
->destAlphaPtr
;
1177 //----- source alpha
1178 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1180 //----- result alpha and non-isolated group element correction
1181 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
1184 //----- result color
1190 cResult0
= state
->rgbTransferR
[(Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
1191 aSrc
* pipe
->cSrc
[0]) / alpha2
)];
1192 cResult1
= state
->rgbTransferG
[(Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
1193 aSrc
* pipe
->cSrc
[1]) / alpha2
)];
1194 cResult2
= state
->rgbTransferB
[(Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
1195 aSrc
* pipe
->cSrc
[2]) / alpha2
)];
1198 //----- write destination pixel
1199 *pipe
->destColorPtr
++ = cResult2
;
1200 *pipe
->destColorPtr
++ = cResult1
;
1201 *pipe
->destColorPtr
++ = cResult0
;
1202 *pipe
->destAlphaPtr
++ = aResult
;
1209 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1210 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1211 // !pipe->nonIsolatedGroup &&
1212 // bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr
1213 void Splash::pipeRunAACMYK8(SplashPipe
*pipe
) {
1214 Guchar aSrc
, aDest
, alpha2
, aResult
;
1216 Guchar cResult0
, cResult1
, cResult2
, cResult3
;
1218 //----- read destination pixel
1219 cDest
[0] = pipe
->destColorPtr
[0];
1220 cDest
[1] = pipe
->destColorPtr
[1];
1221 cDest
[2] = pipe
->destColorPtr
[2];
1222 cDest
[3] = pipe
->destColorPtr
[3];
1223 aDest
= *pipe
->destAlphaPtr
;
1225 //----- source alpha
1226 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1228 //----- result alpha and non-isolated group element correction
1229 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
1232 //----- result color
1239 cResult0
= state
->cmykTransferC
[(Guchar
)(((alpha2
- aSrc
) * cDest
[0] +
1240 aSrc
* pipe
->cSrc
[0]) / alpha2
)];
1241 cResult1
= state
->cmykTransferM
[(Guchar
)(((alpha2
- aSrc
) * cDest
[1] +
1242 aSrc
* pipe
->cSrc
[1]) / alpha2
)];
1243 cResult2
= state
->cmykTransferY
[(Guchar
)(((alpha2
- aSrc
) * cDest
[2] +
1244 aSrc
* pipe
->cSrc
[2]) / alpha2
)];
1245 cResult3
= state
->cmykTransferK
[(Guchar
)(((alpha2
- aSrc
) * cDest
[3] +
1246 aSrc
* pipe
->cSrc
[3]) / alpha2
)];
1249 //----- write destination pixel
1250 if (state
->overprintMask
& 1) {
1251 pipe
->destColorPtr
[0] = (state
->overprintAdditive
&& pipe
->shape
!= 0) ?
1252 std::min
<int>(pipe
->destColorPtr
[0] + cResult0
, 255) :
1255 if (state
->overprintMask
& 2) {
1256 pipe
->destColorPtr
[1] = (state
->overprintAdditive
&& pipe
->shape
!= 0) ?
1257 std::min
<int>(pipe
->destColorPtr
[1] + cResult1
, 255) :
1260 if (state
->overprintMask
& 4) {
1261 pipe
->destColorPtr
[2] = (state
->overprintAdditive
&& pipe
->shape
!= 0) ?
1262 std::min
<int>(pipe
->destColorPtr
[2] + cResult2
, 255) :
1265 if (state
->overprintMask
& 8) {
1266 pipe
->destColorPtr
[3] = (state
->overprintAdditive
&& pipe
->shape
!= 0) ?
1267 std::min
<int>(pipe
->destColorPtr
[3] + cResult3
, 255) :
1270 pipe
->destColorPtr
+= 4;
1271 *pipe
->destAlphaPtr
++ = aResult
;
1277 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1278 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1279 // !pipe->nonIsolatedGroup &&
1280 // bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr
1281 void Splash::pipeRunAADeviceN8(SplashPipe
*pipe
) {
1282 Guchar aSrc
, aDest
, alpha2
, aResult
;
1284 Guchar cResult
[SPOT_NCOMPS
+4];
1287 //----- read destination pixel
1288 for (cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
1289 cDest
[cp
] = pipe
->destColorPtr
[cp
];
1290 aDest
= *pipe
->destAlphaPtr
;
1292 //----- source alpha
1293 aSrc
= div255(pipe
->aInput
* pipe
->shape
);
1295 //----- result alpha and non-isolated group element correction
1296 aResult
= aSrc
+ aDest
- div255(aSrc
* aDest
);
1299 //----- result color
1301 for (cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
1304 for (cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
1305 cResult
[cp
] = state
->deviceNTransfer
[cp
][(Guchar
)(((alpha2
- aSrc
) * cDest
[cp
] +
1306 aSrc
* pipe
->cSrc
[cp
]) / alpha2
)];
1309 //----- write destination pixel
1311 for (cp
=0; cp
< SPOT_NCOMPS
+4; cp
++) {
1312 if (state
->overprintMask
& mask
) {
1313 pipe
->destColorPtr
[cp
] = cResult
[cp
];
1317 pipe
->destColorPtr
+= (SPOT_NCOMPS
+4);
1318 *pipe
->destAlphaPtr
++ = aResult
;
1324 inline void Splash::pipeSetXY(SplashPipe
*pipe
, int x
, int y
) {
1327 if (state
->softMask
) {
1329 &state
->softMask
->data
[y
* state
->softMask
->rowSize
+ x
];
1331 switch (bitmap
->mode
) {
1332 case splashModeMono1
:
1333 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ (x
>> 3)];
1334 pipe
->destColorMask
= 0x80 >> (x
& 7);
1336 case splashModeMono8
:
1337 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ x
];
1339 case splashModeRGB8
:
1340 case splashModeBGR8
:
1341 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ 3 * x
];
1343 case splashModeXBGR8
:
1344 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ 4 * x
];
1347 case splashModeCMYK8
:
1348 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ 4 * x
];
1350 case splashModeDeviceN8
:
1351 pipe
->destColorPtr
= &bitmap
->data
[y
* bitmap
->rowSize
+ (SPOT_NCOMPS
+ 4) * x
];
1355 if (bitmap
->alpha
) {
1356 pipe
->destAlphaPtr
= &bitmap
->alpha
[y
* bitmap
->width
+ x
];
1358 pipe
->destAlphaPtr
= NULL
;
1360 if (state
->inNonIsolatedGroup
&& alpha0Bitmap
->alpha
) {
1362 &alpha0Bitmap
->alpha
[(alpha0Y
+ y
) * alpha0Bitmap
->width
+
1365 pipe
->alpha0Ptr
= NULL
;
1369 inline void Splash::pipeIncX(SplashPipe
*pipe
) {
1371 if (state
->softMask
) {
1372 ++pipe
->softMaskPtr
;
1374 switch (bitmap
->mode
) {
1375 case splashModeMono1
:
1376 if (!(pipe
->destColorMask
>>= 1)) {
1377 pipe
->destColorMask
= 0x80;
1378 ++pipe
->destColorPtr
;
1381 case splashModeMono8
:
1382 ++pipe
->destColorPtr
;
1384 case splashModeRGB8
:
1385 case splashModeBGR8
:
1386 pipe
->destColorPtr
+= 3;
1388 case splashModeXBGR8
:
1389 pipe
->destColorPtr
+= 4;
1392 case splashModeCMYK8
:
1393 pipe
->destColorPtr
+= 4;
1395 case splashModeDeviceN8
:
1396 pipe
->destColorPtr
+= (SPOT_NCOMPS
+4);
1400 if (pipe
->destAlphaPtr
) {
1401 ++pipe
->destAlphaPtr
;
1403 if (pipe
->alpha0Ptr
) {
1408 inline void Splash::drawPixel(SplashPipe
*pipe
, int x
, int y
, GBool noClip
) {
1409 if (unlikely(y
< 0))
1412 if (noClip
|| state
->clip
->test(x
, y
)) {
1413 pipeSetXY(pipe
, x
, y
);
1414 (this->*pipe
->run
)(pipe
);
1420 inline void Splash::drawAAPixelInit() {
1424 inline void Splash::drawAAPixel(SplashPipe
*pipe
, int x
, int y
) {
1425 #if splashAASize == 4
1426 static int bitCount4
[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
1427 1, 2, 2, 3, 2, 3, 3, 4 };
1435 if (x
< 0 || x
>= bitmap
->width
||
1436 y
< state
->clip
->getYMinI() || y
> state
->clip
->getYMaxI()) {
1442 memset(aaBuf
->getDataPtr(), 0xff,
1443 aaBuf
->getRowSize() * aaBuf
->getHeight());
1445 x1
= bitmap
->width
- 1;
1446 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
);
1450 // compute the shape value
1451 #if splashAASize == 4
1452 p
= aaBuf
->getDataPtr() + (x
>> 1);
1453 w
= aaBuf
->getRowSize();
1455 t
= bitCount4
[*p
& 0x0f] + bitCount4
[p
[w
] & 0x0f] +
1456 bitCount4
[p
[2*w
] & 0x0f] + bitCount4
[p
[3*w
] & 0x0f];
1458 t
= bitCount4
[*p
>> 4] + bitCount4
[p
[w
] >> 4] +
1459 bitCount4
[p
[2*w
] >> 4] + bitCount4
[p
[3*w
] >> 4];
1463 for (yy
= 0; yy
< splashAASize
; ++yy
) {
1464 for (xx
= 0; xx
< splashAASize
; ++xx
) {
1465 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() +
1466 ((x
* splashAASize
+ xx
) >> 3);
1467 t
+= (*p
>> (7 - ((x
* splashAASize
+ xx
) & 7))) & 1;
1474 pipeSetXY(pipe
, x
, y
);
1475 pipe
->shape
= div255(aaGamma
[t
] * pipe
->shape
);
1476 (this->*pipe
->run
)(pipe
);
1482 inline void Splash::drawSpan(SplashPipe
*pipe
, int x0
, int x1
, int y
,
1487 pipeSetXY(pipe
, x0
, y
);
1488 for (x
= x0
; x
<= x1
; ++x
) {
1489 (this->*pipe
->run
)(pipe
);
1495 if (x0
< state
->clip
->getXMinI()) {
1496 x0
= state
->clip
->getXMinI();
1498 if (x1
> state
->clip
->getXMaxI()) {
1499 x1
= state
->clip
->getXMaxI();
1501 pipeSetXY(pipe
, x0
, y
);
1502 for (x
= x0
; x
<= x1
; ++x
) {
1503 if (state
->clip
->test(x
, y
)) {
1504 (this->*pipe
->run
)(pipe
);
1514 inline void Splash::drawAALine(SplashPipe
*pipe
, int x0
, int x1
, int y
, GBool adjustLine
, Guchar lineOpacity
) {
1515 #if splashAASize == 4
1516 static int bitCount4
[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
1517 1, 2, 2, 3, 2, 3, 3, 4 };
1518 SplashColorPtr p0
, p1
, p2
, p3
;
1526 #if splashAASize == 4
1527 p0
= aaBuf
->getDataPtr() + (x0
>> 1);
1528 p1
= p0
+ aaBuf
->getRowSize();
1529 p2
= p1
+ aaBuf
->getRowSize();
1530 p3
= p2
+ aaBuf
->getRowSize();
1532 pipeSetXY(pipe
, x0
, y
);
1533 for (x
= x0
; x
<= x1
; ++x
) {
1535 // compute the shape value
1536 #if splashAASize == 4
1538 t
= bitCount4
[*p0
& 0x0f] + bitCount4
[*p1
& 0x0f] +
1539 bitCount4
[*p2
& 0x0f] + bitCount4
[*p3
& 0x0f];
1540 ++p0
; ++p1
; ++p2
; ++p3
;
1542 t
= bitCount4
[*p0
>> 4] + bitCount4
[*p1
>> 4] +
1543 bitCount4
[*p2
>> 4] + bitCount4
[*p3
>> 4];
1547 for (yy
= 0; yy
< splashAASize
; ++yy
) {
1548 for (xx
= 0; xx
< splashAASize
; ++xx
) {
1549 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() +
1550 ((x
* splashAASize
+ xx
) >> 3);
1551 t
+= (*p
>> (7 - ((x
* splashAASize
+ xx
) & 7))) & 1;
1557 pipe
->shape
= (adjustLine
) ? div255((int) lineOpacity
* (double)aaGamma
[t
]) : (double)aaGamma
[t
];
1558 (this->*pipe
->run
)(pipe
);
1567 //------------------------------------------------------------------------
1569 // Transform a point from user space to device space.
1570 inline void Splash::transform(SplashCoord
*matrix
,
1571 SplashCoord xi
, SplashCoord yi
,
1572 SplashCoord
*xo
, SplashCoord
*yo
) {
1574 // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
1576 *xo
= xi
* matrix
[0] + yi
* matrix
[2] + matrix
[4];
1577 *yo
= xi
* matrix
[1] + yi
* matrix
[3] + matrix
[5];
1580 //------------------------------------------------------------------------
1582 //------------------------------------------------------------------------
1584 Splash::Splash(SplashBitmap
*bitmapA
, GBool vectorAntialiasA
,
1585 SplashScreenParams
*screenParams
) {
1589 vectorAntialias
= vectorAntialiasA
;
1591 state
= new SplashState(bitmap
->width
, bitmap
->height
, vectorAntialias
,
1593 if (vectorAntialias
) {
1594 aaBuf
= new SplashBitmap(splashAASize
* bitmap
->width
, splashAASize
,
1595 1, splashModeMono1
, gFalse
);
1596 for (i
= 0; i
<= splashAASize
* splashAASize
; ++i
) {
1597 aaGamma
[i
] = (Guchar
)splashRound(
1598 splashPow((SplashCoord
)i
/
1599 (SplashCoord
)(splashAASize
* splashAASize
),
1600 splashAAGamma
) * 255);
1606 thinLineMode
= splashThinLineDefault
;
1609 alpha0Bitmap
= NULL
;
1612 Splash::Splash(SplashBitmap
*bitmapA
, GBool vectorAntialiasA
,
1613 SplashScreen
*screenA
) {
1618 vectorAntialias
= vectorAntialiasA
;
1619 state
= new SplashState(bitmap
->width
, bitmap
->height
, vectorAntialias
,
1621 if (vectorAntialias
) {
1622 aaBuf
= new SplashBitmap(splashAASize
* bitmap
->width
, splashAASize
,
1623 1, splashModeMono1
, gFalse
);
1624 for (i
= 0; i
<= splashAASize
* splashAASize
; ++i
) {
1625 aaGamma
[i
] = (Guchar
)splashRound(
1626 splashPow((SplashCoord
)i
/
1627 (SplashCoord
)(splashAASize
* splashAASize
),
1628 splashAAGamma
) * 255);
1634 thinLineMode
= splashThinLineDefault
;
1637 alpha0Bitmap
= NULL
;
1641 while (state
->next
) {
1645 if (vectorAntialias
) {
1650 //------------------------------------------------------------------------
1652 //------------------------------------------------------------------------
1654 SplashCoord
*Splash::getMatrix() {
1655 return state
->matrix
;
1658 SplashPattern
*Splash::getStrokePattern() {
1659 return state
->strokePattern
;
1662 SplashPattern
*Splash::getFillPattern() {
1663 return state
->fillPattern
;
1666 SplashScreen
*Splash::getScreen() {
1667 return state
->screen
;
1670 SplashBlendFunc
Splash::getBlendFunc() {
1671 return state
->blendFunc
;
1674 SplashCoord
Splash::getStrokeAlpha() {
1675 return state
->strokeAlpha
;
1678 SplashCoord
Splash::getFillAlpha() {
1679 return state
->fillAlpha
;
1682 SplashCoord
Splash::getLineWidth() {
1683 return state
->lineWidth
;
1686 int Splash::getLineCap() {
1687 return state
->lineCap
;
1690 int Splash::getLineJoin() {
1691 return state
->lineJoin
;
1694 SplashCoord
Splash::getMiterLimit() {
1695 return state
->miterLimit
;
1698 SplashCoord
Splash::getFlatness() {
1699 return state
->flatness
;
1702 SplashCoord
*Splash::getLineDash() {
1703 return state
->lineDash
;
1706 int Splash::getLineDashLength() {
1707 return state
->lineDashLength
;
1710 SplashCoord
Splash::getLineDashPhase() {
1711 return state
->lineDashPhase
;
1714 GBool
Splash::getStrokeAdjust() {
1715 return state
->strokeAdjust
;
1718 SplashClip
*Splash::getClip() {
1722 SplashBitmap
*Splash::getSoftMask() {
1723 return state
->softMask
;
1726 GBool
Splash::getInNonIsolatedGroup() {
1727 return state
->inNonIsolatedGroup
;
1730 //------------------------------------------------------------------------
1732 //------------------------------------------------------------------------
1734 void Splash::setMatrix(SplashCoord
*matrix
) {
1735 memcpy(state
->matrix
, matrix
, 6 * sizeof(SplashCoord
));
1738 void Splash::setStrokePattern(SplashPattern
*strokePattern
) {
1739 state
->setStrokePattern(strokePattern
);
1742 void Splash::setFillPattern(SplashPattern
*fillPattern
) {
1743 state
->setFillPattern(fillPattern
);
1746 void Splash::setScreen(SplashScreen
*screen
) {
1747 state
->setScreen(screen
);
1750 void Splash::setBlendFunc(SplashBlendFunc func
) {
1751 state
->blendFunc
= func
;
1754 void Splash::setStrokeAlpha(SplashCoord alpha
) {
1755 state
->strokeAlpha
= alpha
;
1758 void Splash::setFillAlpha(SplashCoord alpha
) {
1759 state
->fillAlpha
= alpha
;
1762 void Splash::setFillOverprint(GBool fop
) {
1763 state
->fillOverprint
= fop
;
1766 void Splash::setStrokeOverprint(GBool gop
) {
1767 state
->strokeOverprint
= gop
;
1770 void Splash::setOverprintMode(int opm
) {
1771 state
->overprintMode
= opm
;
1774 void Splash::setLineWidth(SplashCoord lineWidth
) {
1775 state
->lineWidth
= lineWidth
;
1778 void Splash::setLineCap(int lineCap
) {
1779 state
->lineCap
= lineCap
;
1782 void Splash::setLineJoin(int lineJoin
) {
1783 state
->lineJoin
= lineJoin
;
1786 void Splash::setMiterLimit(SplashCoord miterLimit
) {
1787 state
->miterLimit
= miterLimit
;
1790 void Splash::setFlatness(SplashCoord flatness
) {
1792 state
->flatness
= 1;
1794 state
->flatness
= flatness
;
1798 void Splash::setLineDash(SplashCoord
*lineDash
, int lineDashLength
,
1799 SplashCoord lineDashPhase
) {
1800 state
->setLineDash(lineDash
, lineDashLength
, lineDashPhase
);
1803 void Splash::setStrokeAdjust(GBool strokeAdjust
) {
1804 state
->strokeAdjust
= strokeAdjust
;
1807 void Splash::clipResetToRect(SplashCoord x0
, SplashCoord y0
,
1808 SplashCoord x1
, SplashCoord y1
) {
1809 state
->clip
->resetToRect(x0
, y0
, x1
, y1
);
1812 SplashError
Splash::clipToRect(SplashCoord x0
, SplashCoord y0
,
1813 SplashCoord x1
, SplashCoord y1
) {
1814 return state
->clip
->clipToRect(x0
, y0
, x1
, y1
);
1817 SplashError
Splash::clipToPath(SplashPath
*path
, GBool eo
) {
1818 return state
->clip
->clipToPath(path
, state
->matrix
, state
->flatness
, eo
);
1821 void Splash::setSoftMask(SplashBitmap
*softMask
) {
1822 state
->setSoftMask(softMask
);
1825 void Splash::setInNonIsolatedGroup(SplashBitmap
*alpha0BitmapA
,
1826 int alpha0XA
, int alpha0YA
) {
1827 alpha0Bitmap
= alpha0BitmapA
;
1830 state
->inNonIsolatedGroup
= gTrue
;
1833 void Splash::setTransfer(Guchar
*red
, Guchar
*green
, Guchar
*blue
,
1835 state
->setTransfer(red
, green
, blue
, gray
);
1838 void Splash::setOverprintMask(Guint overprintMask
, GBool additive
) {
1839 state
->overprintMask
= overprintMask
;
1840 state
->overprintAdditive
= additive
;
1843 //------------------------------------------------------------------------
1844 // state save/restore
1845 //------------------------------------------------------------------------
1847 void Splash::saveState() {
1848 SplashState
*newState
;
1850 newState
= state
->copy();
1851 newState
->next
= state
;
1855 SplashError
Splash::restoreState() {
1856 SplashState
*oldState
;
1859 return splashErrNoSave
;
1862 state
= state
->next
;
1867 //------------------------------------------------------------------------
1868 // drawing operations
1869 //------------------------------------------------------------------------
1871 void Splash::clear(SplashColorPtr color
, Guchar alpha
) {
1872 SplashColorPtr row
, p
;
1876 switch (bitmap
->mode
) {
1877 case splashModeMono1
:
1878 mono
= (color
[0] & 0x80) ? 0xff : 0x00;
1879 if (bitmap
->rowSize
< 0) {
1880 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1881 mono
, -bitmap
->rowSize
* bitmap
->height
);
1883 memset(bitmap
->data
, mono
, bitmap
->rowSize
* bitmap
->height
);
1886 case splashModeMono8
:
1887 if (bitmap
->rowSize
< 0) {
1888 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1889 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1891 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1894 case splashModeRGB8
:
1895 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1896 if (bitmap
->rowSize
< 0) {
1897 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1898 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1900 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1904 for (y
= 0; y
< bitmap
->height
; ++y
) {
1906 for (x
= 0; x
< bitmap
->width
; ++x
) {
1911 row
+= bitmap
->rowSize
;
1915 case splashModeXBGR8
:
1916 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1917 if (bitmap
->rowSize
< 0) {
1918 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1919 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1921 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1925 for (y
= 0; y
< bitmap
->height
; ++y
) {
1927 for (x
= 0; x
< bitmap
->width
; ++x
) {
1933 row
+= bitmap
->rowSize
;
1937 case splashModeBGR8
:
1938 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1939 if (bitmap
->rowSize
< 0) {
1940 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1941 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1943 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1947 for (y
= 0; y
< bitmap
->height
; ++y
) {
1949 for (x
= 0; x
< bitmap
->width
; ++x
) {
1954 row
+= bitmap
->rowSize
;
1959 case splashModeCMYK8
:
1960 if (color
[0] == color
[1] && color
[1] == color
[2] && color
[2] == color
[3]) {
1961 if (bitmap
->rowSize
< 0) {
1962 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1963 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1965 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1969 for (y
= 0; y
< bitmap
->height
; ++y
) {
1971 for (x
= 0; x
< bitmap
->width
; ++x
) {
1977 row
+= bitmap
->rowSize
;
1981 case splashModeDeviceN8
:
1983 for (y
= 0; y
< bitmap
->height
; ++y
) {
1985 for (x
= 0; x
< bitmap
->width
; ++x
) {
1986 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
1989 row
+= bitmap
->rowSize
;
1995 if (bitmap
->alpha
) {
1996 memset(bitmap
->alpha
, alpha
, bitmap
->width
* bitmap
->height
);
2001 updateModX(bitmap
->width
- 1);
2002 updateModY(bitmap
->height
- 1);
2005 SplashError
Splash::stroke(SplashPath
*path
) {
2006 SplashPath
*path2
, *dPath
;
2007 SplashCoord d1
, d2
, t1
, t2
, w
;
2010 printf("stroke [dash:%d] [width:%.2f]:\n",
2011 state
->lineDashLength
, (double)state
->lineWidth
);
2014 opClipRes
= splashClipAllOutside
;
2015 if (path
->length
== 0) {
2016 return splashErrEmptyPath
;
2018 path2
= flattenPath(path
, state
->matrix
, state
->flatness
);
2019 if (state
->lineDashLength
> 0) {
2020 dPath
= makeDashedPath(path2
);
2023 if (path2
->length
== 0) {
2025 return splashErrEmptyPath
;
2029 // transform a unit square, and take the half the max of the two
2030 // diagonals; the product of this number and the line width is the
2031 // (approximate) transformed line width
2032 t1
= state
->matrix
[0] + state
->matrix
[2];
2033 t2
= state
->matrix
[1] + state
->matrix
[3];
2034 d1
= t1
* t1
+ t2
* t2
;
2035 t1
= state
->matrix
[0] - state
->matrix
[2];
2036 t2
= state
->matrix
[1] - state
->matrix
[3];
2037 d2
= t1
* t1
+ t2
* t2
;
2043 d1
* state
->lineWidth
* state
->lineWidth
< minLineWidth
* minLineWidth
) {
2044 w
= minLineWidth
/ splashSqrt(d1
);
2045 strokeWide(path2
, w
);
2046 } else if (bitmap
->mode
== splashModeMono1
) {
2047 // this gets close to Adobe's behavior in mono mode
2048 if (d1
* state
->lineWidth
<= 2) {
2049 strokeNarrow(path2
);
2051 strokeWide(path2
, state
->lineWidth
);
2054 if (state
->lineWidth
== 0) {
2055 strokeNarrow(path2
);
2057 strokeWide(path2
, state
->lineWidth
);
2065 void Splash::strokeNarrow(SplashPath
*path
) {
2068 SplashXPathSeg
*seg
;
2069 int x0
, x1
, y0
, y1
, xa
, xb
, y
;
2071 SplashClipResult clipRes
;
2075 nClipRes
[0] = nClipRes
[1] = nClipRes
[2] = 0;
2077 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gFalse
);
2079 pipeInit(&pipe
, 0, 0, state
->strokePattern
, NULL
,
2080 (Guchar
)splashRound(state
->strokeAlpha
* 255),
2083 for (i
= 0, seg
= xPath
->segs
; i
< xPath
->length
; ++i
, ++seg
) {
2084 if (seg
->y0
<= seg
->y1
) {
2085 y0
= splashFloor(seg
->y0
);
2086 y1
= splashFloor(seg
->y1
);
2087 x0
= splashFloor(seg
->x0
);
2088 x1
= splashFloor(seg
->x1
);
2090 y0
= splashFloor(seg
->y1
);
2091 y1
= splashFloor(seg
->y0
);
2092 x0
= splashFloor(seg
->x1
);
2093 x1
= splashFloor(seg
->x0
);
2095 if ((clipRes
= state
->clip
->testRect(x0
<= x1
? x0
: x1
, y0
,
2096 x0
<= x1
? x1
: x0
, y1
))
2097 != splashClipAllOutside
) {
2100 drawSpan(&pipe
, x0
, x1
, y0
, clipRes
== splashClipAllInside
);
2102 drawSpan(&pipe
, x1
, x0
, y0
, clipRes
== splashClipAllInside
);
2106 if (y0
< state
->clip
->getYMinI()) {
2107 y0
= state
->clip
->getYMinI();
2108 x0
= splashFloor(seg
->x0
+ ((SplashCoord
)y0
- seg
->y0
) * dxdy
);
2110 if (y1
> state
->clip
->getYMaxI()) {
2111 y1
= state
->clip
->getYMaxI();
2112 x1
= splashFloor(seg
->x0
+ ((SplashCoord
)y1
- seg
->y0
) * dxdy
);
2116 for (y
= y0
; y
<= y1
; ++y
) {
2118 xb
= splashFloor(seg
->x0
+
2119 ((SplashCoord
)y
+ 1 - seg
->y0
) * dxdy
);
2124 drawPixel(&pipe
, xa
, y
, clipRes
== splashClipAllInside
);
2126 drawSpan(&pipe
, xa
, xb
- 1, y
, clipRes
== splashClipAllInside
);
2132 for (y
= y0
; y
<= y1
; ++y
) {
2134 xb
= splashFloor(seg
->x0
+
2135 ((SplashCoord
)y
+ 1 - seg
->y0
) * dxdy
);
2140 drawPixel(&pipe
, xa
, y
, clipRes
== splashClipAllInside
);
2142 drawSpan(&pipe
, xb
+ 1, xa
, y
, clipRes
== splashClipAllInside
);
2149 ++nClipRes
[clipRes
];
2151 if (nClipRes
[splashClipPartial
] ||
2152 (nClipRes
[splashClipAllInside
] && nClipRes
[splashClipAllOutside
])) {
2153 opClipRes
= splashClipPartial
;
2154 } else if (nClipRes
[splashClipAllInside
]) {
2155 opClipRes
= splashClipAllInside
;
2157 opClipRes
= splashClipAllOutside
;
2163 void Splash::strokeWide(SplashPath
*path
, SplashCoord w
) {
2166 path2
= makeStrokePath(path
, w
, gFalse
);
2167 fillWithPattern(path2
, gFalse
, state
->strokePattern
, state
->strokeAlpha
);
2171 SplashPath
*Splash::flattenPath(SplashPath
*path
, SplashCoord
*matrix
,
2172 SplashCoord flatness
) {
2174 SplashCoord flatness2
;
2178 fPath
= new SplashPath();
2180 flatness2
= flatness
;
2182 flatness2
= flatness
* flatness
;
2185 while (i
< path
->length
) {
2186 flag
= path
->flags
[i
];
2187 if (flag
& splashPathFirst
) {
2188 fPath
->moveTo(path
->pts
[i
].x
, path
->pts
[i
].y
);
2191 if (flag
& splashPathCurve
) {
2192 flattenCurve(path
->pts
[i
-1].x
, path
->pts
[i
-1].y
,
2193 path
->pts
[i
].x
, path
->pts
[i
].y
,
2194 path
->pts
[i
+1].x
, path
->pts
[i
+1].y
,
2195 path
->pts
[i
+2].x
, path
->pts
[i
+2].y
,
2196 matrix
, flatness2
, fPath
);
2199 fPath
->lineTo(path
->pts
[i
].x
, path
->pts
[i
].y
);
2202 if (path
->flags
[i
-1] & splashPathClosed
) {
2210 void Splash::flattenCurve(SplashCoord x0
, SplashCoord y0
,
2211 SplashCoord x1
, SplashCoord y1
,
2212 SplashCoord x2
, SplashCoord y2
,
2213 SplashCoord x3
, SplashCoord y3
,
2214 SplashCoord
*matrix
, SplashCoord flatness2
,
2215 SplashPath
*fPath
) {
2216 SplashCoord cx
[splashMaxCurveSplits
+ 1][3];
2217 SplashCoord cy
[splashMaxCurveSplits
+ 1][3];
2218 int cNext
[splashMaxCurveSplits
+ 1];
2219 SplashCoord xl0
, xl1
, xl2
, xr0
, xr1
, xr2
, xr3
, xx1
, xx2
, xh
;
2220 SplashCoord yl0
, yl1
, yl2
, yr0
, yr1
, yr2
, yr3
, yy1
, yy2
, yh
;
2221 SplashCoord dx
, dy
, mx
, my
, tx
, ty
, d1
, d2
;
2226 p2
= splashMaxCurveSplits
;
2227 cx
[p1
][0] = x0
; cy
[p1
][0] = y0
;
2228 cx
[p1
][1] = x1
; cy
[p1
][1] = y1
;
2229 cx
[p1
][2] = x2
; cy
[p1
][2] = y2
;
2230 cx
[p2
][0] = x3
; cy
[p2
][0] = y3
;
2233 while (p1
< splashMaxCurveSplits
) {
2235 // get the next segment
2236 xl0
= cx
[p1
][0]; yl0
= cy
[p1
][0];
2237 xx1
= cx
[p1
][1]; yy1
= cy
[p1
][1];
2238 xx2
= cx
[p1
][2]; yy2
= cy
[p1
][2];
2240 xr3
= cx
[p2
][0]; yr3
= cy
[p2
][0];
2242 // compute the distances (in device space) from the control points
2243 // to the midpoint of the straight line (this is a bit of a hack,
2244 // but it's much faster than computing the actual distances to the
2246 transform(matrix
, (xl0
+ xr3
) * 0.5, (yl0
+ yr3
) * 0.5, &mx
, &my
);
2247 transform(matrix
, xx1
, yy1
, &tx
, &ty
);
2249 d1
= splashDist(tx
, ty
, mx
, my
);
2255 transform(matrix
, xx2
, yy2
, &tx
, &ty
);
2257 d2
= splashDist(tx
, ty
, mx
, my
);
2264 // if the curve is flat enough, or no more subdivisions are
2265 // allowed, add the straight line segment
2266 if (p2
- p1
== 1 || (d1
<= flatness2
&& d2
<= flatness2
)) {
2267 fPath
->lineTo(xr3
, yr3
);
2270 // otherwise, subdivide the curve
2272 xl1
= splashAvg(xl0
, xx1
);
2273 yl1
= splashAvg(yl0
, yy1
);
2274 xh
= splashAvg(xx1
, xx2
);
2275 yh
= splashAvg(yy1
, yy2
);
2276 xl2
= splashAvg(xl1
, xh
);
2277 yl2
= splashAvg(yl1
, yh
);
2278 xr2
= splashAvg(xx2
, xr3
);
2279 yr2
= splashAvg(yy2
, yr3
);
2280 xr1
= splashAvg(xh
, xr2
);
2281 yr1
= splashAvg(yh
, yr2
);
2282 xr0
= splashAvg(xl2
, xr1
);
2283 yr0
= splashAvg(yl2
, yr1
);
2284 // add the new subdivision points
2286 cx
[p1
][1] = xl1
; cy
[p1
][1] = yl1
;
2287 cx
[p1
][2] = xl2
; cy
[p1
][2] = yl2
;
2289 cx
[p3
][0] = xr0
; cy
[p3
][0] = yr0
;
2290 cx
[p3
][1] = xr1
; cy
[p3
][1] = yr1
;
2291 cx
[p3
][2] = xr2
; cy
[p3
][2] = yr2
;
2297 SplashPath
*Splash::makeDashedPath(SplashPath
*path
) {
2299 SplashCoord lineDashTotal
;
2300 SplashCoord lineDashStartPhase
, lineDashDist
, segLen
;
2301 SplashCoord x0
, y0
, x1
, y1
, xa
, ya
;
2302 GBool lineDashStartOn
, lineDashOn
, newPath
;
2303 int lineDashStartIdx
, lineDashIdx
;
2307 for (i
= 0; i
< state
->lineDashLength
; ++i
) {
2308 lineDashTotal
+= state
->lineDash
[i
];
2310 // Acrobat simply draws nothing if the dash array is [0]
2311 if (lineDashTotal
== 0) {
2312 return new SplashPath();
2314 lineDashStartPhase
= state
->lineDashPhase
;
2315 i
= splashFloor(lineDashStartPhase
/ lineDashTotal
);
2316 lineDashStartPhase
-= (SplashCoord
)i
* lineDashTotal
;
2317 lineDashStartOn
= gTrue
;
2318 lineDashStartIdx
= 0;
2319 if (lineDashStartPhase
> 0) {
2320 while (lineDashStartIdx
< state
->lineDashLength
&& lineDashStartPhase
>= state
->lineDash
[lineDashStartIdx
]) {
2321 lineDashStartOn
= !lineDashStartOn
;
2322 lineDashStartPhase
-= state
->lineDash
[lineDashStartIdx
];
2325 if (unlikely(lineDashStartIdx
== state
->lineDashLength
)) {
2326 return new SplashPath();
2330 dPath
= new SplashPath();
2332 // process each subpath
2334 while (i
< path
->length
) {
2336 // find the end of the subpath
2338 j
< path
->length
- 1 && !(path
->flags
[j
] & splashPathLast
);
2341 // initialize the dash parameters
2342 lineDashOn
= lineDashStartOn
;
2343 lineDashIdx
= lineDashStartIdx
;
2344 lineDashDist
= state
->lineDash
[lineDashIdx
] - lineDashStartPhase
;
2346 // process each segment of the subpath
2348 for (k
= i
; k
< j
; ++k
) {
2351 x0
= path
->pts
[k
].x
;
2352 y0
= path
->pts
[k
].y
;
2353 x1
= path
->pts
[k
+1].x
;
2354 y1
= path
->pts
[k
+1].y
;
2355 segLen
= splashDist(x0
, y0
, x1
, y1
);
2357 // process the segment
2358 while (segLen
> 0) {
2360 if (lineDashDist
>= segLen
) {
2363 dPath
->moveTo(x0
, y0
);
2366 dPath
->lineTo(x1
, y1
);
2368 lineDashDist
-= segLen
;
2372 xa
= x0
+ (lineDashDist
/ segLen
) * (x1
- x0
);
2373 ya
= y0
+ (lineDashDist
/ segLen
) * (y1
- y0
);
2376 dPath
->moveTo(x0
, y0
);
2379 dPath
->lineTo(xa
, ya
);
2383 segLen
-= lineDashDist
;
2387 // get the next entry in the dash array
2388 if (lineDashDist
<= 0) {
2389 lineDashOn
= !lineDashOn
;
2390 if (++lineDashIdx
== state
->lineDashLength
) {
2393 lineDashDist
= state
->lineDash
[lineDashIdx
];
2401 if (dPath
->length
== 0) {
2402 GBool allSame
= gTrue
;
2403 for (int i
= 0; allSame
&& i
< path
->length
- 1; ++i
) {
2404 allSame
= path
->pts
[i
].x
== path
->pts
[i
+ 1].x
&& path
->pts
[i
].y
== path
->pts
[i
+ 1].y
;
2407 x0
= path
->pts
[0].x
;
2408 y0
= path
->pts
[0].y
;
2409 dPath
->moveTo(x0
, y0
);
2410 dPath
->lineTo(x0
, y0
);
2417 SplashError
Splash::fill(SplashPath
*path
, GBool eo
) {
2419 printf("fill [eo:%d]:\n", eo
);
2422 return fillWithPattern(path
, eo
, state
->fillPattern
, state
->fillAlpha
);
2425 inline void Splash::getBBoxFP(SplashPath
*path
, SplashCoord
*xMinA
, SplashCoord
*yMinA
,
2426 SplashCoord
*xMaxA
, SplashCoord
*yMaxA
) {
2427 SplashCoord xMinFP
, yMinFP
, xMaxFP
, yMaxFP
, tx
, ty
;
2429 // make compiler happy:
2430 xMinFP
= xMaxFP
= yMinFP
= yMaxFP
= 0;
2431 for (int i
= 0; i
< path
->length
; ++i
) {
2432 transform(state
->matrix
, path
->pts
[i
].x
, path
->pts
[i
].y
, &tx
, &ty
);
2434 xMinFP
= xMaxFP
= tx
;
2435 yMinFP
= yMaxFP
= ty
;
2437 if (tx
< xMinFP
) xMinFP
= tx
;
2438 if (tx
> xMaxFP
) xMaxFP
= tx
;
2439 if (ty
< yMinFP
) yMinFP
= ty
;
2440 if (ty
> yMaxFP
) yMaxFP
= ty
;
2450 SplashError
Splash::fillWithPattern(SplashPath
*path
, GBool eo
,
2451 SplashPattern
*pattern
,
2452 SplashCoord alpha
) {
2455 SplashXPathScanner
*scanner
;
2456 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
2457 SplashClipResult clipRes
, clipRes2
;
2458 GBool adjustLine
= gFalse
;
2461 if (path
->length
== 0) {
2462 return splashErrEmptyPath
;
2464 if (pathAllOutside(path
)) {
2465 opClipRes
= splashClipAllOutside
;
2469 // add stroke adjustment hints for filled rectangles -- this only
2470 // applies to paths that consist of a single subpath
2471 // (this appears to match Acrobat's behavior)
2472 if (state
->strokeAdjust
&& !path
->hints
) {
2474 n
= path
->getLength();
2476 !(path
->flags
[0] & splashPathClosed
) &&
2477 !(path
->flags
[1] & splashPathLast
) &&
2478 !(path
->flags
[2] & splashPathLast
)) {
2480 path
->addStrokeAdjustHint(0, 2, 0, 4);
2481 path
->addStrokeAdjustHint(1, 3, 0, 4);
2482 } else if (n
== 5 &&
2483 (path
->flags
[0] & splashPathClosed
) &&
2484 !(path
->flags
[1] & splashPathLast
) &&
2485 !(path
->flags
[2] & splashPathLast
) &&
2486 !(path
->flags
[3] & splashPathLast
)) {
2487 path
->addStrokeAdjustHint(0, 2, 0, 4);
2488 path
->addStrokeAdjustHint(1, 3, 0, 4);
2492 if (thinLineMode
!= splashThinLineDefault
) {
2493 if (state
->clip
->getXMinI() == state
->clip
->getXMaxI()) {
2494 linePosI
= state
->clip
->getXMinI();
2496 } else if (state
->clip
->getXMinI() == state
->clip
->getXMaxI() - 1) {
2498 linePosI
= splashFloor(state
->clip
->getXMin() + state
->lineWidth
);
2499 } else if (state
->clip
->getYMinI() == state
->clip
->getYMaxI()) {
2500 linePosI
= state
->clip
->getYMinI();
2502 } else if (state
->clip
->getYMinI() == state
->clip
->getYMaxI() - 1) {
2504 linePosI
= splashFloor(state
->clip
->getYMin() + state
->lineWidth
);
2508 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
,
2509 adjustLine
, linePosI
);
2510 if (vectorAntialias
&& !inShading
) {
2514 yMinI
= state
->clip
->getYMinI();
2515 yMaxI
= state
->clip
->getYMaxI();
2516 if (vectorAntialias
&& !inShading
) {
2517 yMinI
= yMinI
* splashAASize
;
2518 yMaxI
= (yMaxI
+ 1) * splashAASize
- 1;
2520 scanner
= new SplashXPathScanner(xPath
, eo
, yMinI
, yMaxI
);
2522 // get the min and max x and y values
2523 if (vectorAntialias
&& !inShading
) {
2524 scanner
->getBBoxAA(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
2526 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
2529 if (eo
&& (yMinI
== yMaxI
|| xMinI
== xMaxI
) && thinLineMode
!= splashThinLineDefault
) {
2530 SplashCoord delta
, xMinFP
, yMinFP
, xMaxFP
, yMaxFP
;
2531 getBBoxFP(path
, &xMinFP
, &yMinFP
, &xMaxFP
, &yMaxFP
);
2532 delta
= (yMinI
== yMaxI
) ? yMaxFP
- yMinFP
: xMaxFP
- xMinFP
;
2534 opClipRes
= splashClipAllOutside
;
2542 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
))
2543 != splashClipAllOutside
) {
2544 if (scanner
->hasPartialClip()) {
2545 clipRes
= splashClipPartial
;
2548 pipeInit(&pipe
, 0, yMinI
, pattern
, NULL
, (Guchar
)splashRound(alpha
* 255),
2549 vectorAntialias
&& !inShading
, gFalse
);
2552 if (vectorAntialias
&& !inShading
) {
2553 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
2554 scanner
->renderAALine(aaBuf
, &x0
, &x1
, y
, thinLineMode
!= splashThinLineDefault
&& xMinI
== xMaxI
);
2555 if (clipRes
!= splashClipAllInside
) {
2556 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
, thinLineMode
!= splashThinLineDefault
&& xMinI
== xMaxI
);
2558 Guchar lineShape
= 255;
2559 GBool adjustLine
= gFalse
;
2560 if (thinLineMode
== splashThinLineShape
&& (xMinI
== xMaxI
|| yMinI
== yMaxI
)) {
2561 // compute line shape for thin lines:
2562 SplashCoord mx
, my
, delta
;
2563 transform(state
->matrix
, 0, 0, &mx
, &my
);
2564 transform(state
->matrix
, state
->lineWidth
, 0, &delta
, &my
);
2566 lineShape
= clip255((delta
- mx
) * 255);
2568 drawAALine(&pipe
, x0
, x1
, y
, adjustLine
, lineShape
);
2571 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
2572 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
2573 if (clipRes
== splashClipAllInside
) {
2574 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
2576 // limit the x range
2577 if (x0
< state
->clip
->getXMinI()) {
2578 x0
= state
->clip
->getXMinI();
2580 if (x1
> state
->clip
->getXMaxI()) {
2581 x1
= state
->clip
->getXMaxI();
2583 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
2584 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
2590 opClipRes
= clipRes
;
2597 GBool
Splash::pathAllOutside(SplashPath
*path
) {
2598 SplashCoord xMin1
, yMin1
, xMax1
, yMax1
;
2599 SplashCoord xMin2
, yMin2
, xMax2
, yMax2
;
2601 int xMinI
, yMinI
, xMaxI
, yMaxI
;
2604 xMin1
= xMax1
= path
->pts
[0].x
;
2605 yMin1
= yMax1
= path
->pts
[0].y
;
2606 for (i
= 1; i
< path
->length
; ++i
) {
2607 if (path
->pts
[i
].x
< xMin1
) {
2608 xMin1
= path
->pts
[i
].x
;
2609 } else if (path
->pts
[i
].x
> xMax1
) {
2610 xMax1
= path
->pts
[i
].x
;
2612 if (path
->pts
[i
].y
< yMin1
) {
2613 yMin1
= path
->pts
[i
].y
;
2614 } else if (path
->pts
[i
].y
> yMax1
) {
2615 yMax1
= path
->pts
[i
].y
;
2619 transform(state
->matrix
, xMin1
, yMin1
, &x
, &y
);
2622 transform(state
->matrix
, xMin1
, yMax1
, &x
, &y
);
2625 } else if (x
> xMax2
) {
2630 } else if (y
> yMax2
) {
2633 transform(state
->matrix
, xMax1
, yMin1
, &x
, &y
);
2636 } else if (x
> xMax2
) {
2641 } else if (y
> yMax2
) {
2644 transform(state
->matrix
, xMax1
, yMax1
, &x
, &y
);
2647 } else if (x
> xMax2
) {
2652 } else if (y
> yMax2
) {
2655 xMinI
= splashFloor(xMin2
);
2656 yMinI
= splashFloor(yMin2
);
2657 xMaxI
= splashFloor(xMax2
);
2658 yMaxI
= splashFloor(yMax2
);
2660 return state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
) ==
2661 splashClipAllOutside
;
2664 SplashError
Splash::xorFill(SplashPath
*path
, GBool eo
) {
2667 SplashXPathScanner
*scanner
;
2668 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
2669 SplashClipResult clipRes
, clipRes2
;
2670 SplashBlendFunc origBlendFunc
;
2672 if (path
->length
== 0) {
2673 return splashErrEmptyPath
;
2675 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
);
2677 scanner
= new SplashXPathScanner(xPath
, eo
, state
->clip
->getYMinI(),
2678 state
->clip
->getYMaxI());
2680 // get the min and max x and y values
2681 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
2684 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
))
2685 != splashClipAllOutside
) {
2686 if (scanner
->hasPartialClip()) {
2687 clipRes
= splashClipPartial
;
2690 origBlendFunc
= state
->blendFunc
;
2691 state
->blendFunc
= &blendXor
;
2692 pipeInit(&pipe
, 0, yMinI
, state
->fillPattern
, NULL
, 255, gFalse
, gFalse
);
2695 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
2696 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
2697 if (clipRes
== splashClipAllInside
) {
2698 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
2700 // limit the x range
2701 if (x0
< state
->clip
->getXMinI()) {
2702 x0
= state
->clip
->getXMinI();
2704 if (x1
> state
->clip
->getXMaxI()) {
2705 x1
= state
->clip
->getXMaxI();
2707 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
2708 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
2712 state
->blendFunc
= origBlendFunc
;
2714 opClipRes
= clipRes
;
2721 SplashError
Splash::fillChar(SplashCoord x
, SplashCoord y
,
2722 int c
, SplashFont
*font
) {
2723 SplashGlyphBitmap glyph
;
2725 int x0
, y0
, xFrac
, yFrac
;
2726 SplashClipResult clipRes
;
2729 printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
2730 (double)x
, (double)y
, c
, c
, c
);
2732 transform(state
->matrix
, x
, y
, &xt
, &yt
);
2733 x0
= splashFloor(xt
);
2734 xFrac
= splashFloor((xt
- x0
) * splashFontFraction
);
2735 y0
= splashFloor(yt
);
2736 yFrac
= splashFloor((yt
- y0
) * splashFontFraction
);
2737 if (!font
->getGlyph(c
, xFrac
, yFrac
, &glyph
, x0
, y0
, state
->clip
, &clipRes
)) {
2738 return splashErrNoGlyph
;
2740 if (clipRes
!= splashClipAllOutside
) {
2741 fillGlyph2(x0
, y0
, &glyph
, clipRes
== splashClipAllInside
);
2743 opClipRes
= clipRes
;
2744 if (glyph
.freeData
) {
2750 void Splash::fillGlyph(SplashCoord x
, SplashCoord y
,
2751 SplashGlyphBitmap
*glyph
) {
2755 transform(state
->matrix
, x
, y
, &xt
, &yt
);
2756 x0
= splashFloor(xt
);
2757 y0
= splashFloor(yt
);
2758 SplashClipResult clipRes
= state
->clip
->testRect(x0
- glyph
->x
,
2760 x0
- glyph
->x
+ glyph
->w
- 1,
2761 y0
- glyph
->y
+ glyph
->h
- 1);
2762 if (clipRes
!= splashClipAllOutside
) {
2763 fillGlyph2(x0
, y0
, glyph
, clipRes
== splashClipAllInside
);
2765 opClipRes
= clipRes
;
2768 void Splash::fillGlyph2(int x0
, int y0
, SplashGlyphBitmap
*glyph
, GBool noClip
) {
2773 int x1
, y1
, xx
, xx1
, yy
;
2776 int xStart
= x0
- glyph
->x
;
2777 int yStart
= y0
- glyph
->y
;
2778 int xxLimit
= glyph
->w
;
2779 int yyLimit
= glyph
->h
;
2784 p
+= (glyph
->aa
? glyph
->w
: splashCeil(glyph
->w
/ 8.0)) * -yStart
; // move p to the beginning of the first painted row
2795 xShift
= (-xStart
) % 8;
2801 if (xxLimit
+ xStart
>= bitmap
->width
) xxLimit
= bitmap
->width
- xStart
;
2802 if (yyLimit
+ yStart
>= bitmap
->height
) yyLimit
= bitmap
->height
- yStart
;
2806 pipeInit(&pipe
, xStart
, yStart
,
2807 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
2808 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2809 pipeSetXY(&pipe
, xStart
, y1
);
2810 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; ++xx
, ++x1
) {
2814 (this->*pipe
.run
)(&pipe
);
2824 const int widthEight
= splashCeil(glyph
->w
/ 8.0);
2826 pipeInit(&pipe
, xStart
, yStart
,
2827 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gFalse
, gFalse
);
2828 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2829 pipeSetXY(&pipe
, xStart
, y1
);
2830 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; xx
+= 8) {
2831 alpha0
= (xShift
> 0 ? (p
[xx
/ 8] << xShift
) | (p
[xx
/ 8 + 1] >> (8 - xShift
)) : p
[xx
/ 8]);
2832 for (xx1
= 0; xx1
< 8 && xx
+ xx1
< xxLimit
; ++xx1
, ++x1
) {
2833 if (alpha0
& 0x80) {
2834 (this->*pipe
.run
)(&pipe
);
2848 pipeInit(&pipe
, xStart
, yStart
,
2849 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
2850 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2851 pipeSetXY(&pipe
, xStart
, y1
);
2852 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; ++xx
, ++x1
) {
2853 if (state
->clip
->test(x1
, y1
)) {
2857 (this->*pipe
.run
)(&pipe
);
2870 const int widthEight
= splashCeil(glyph
->w
/ 8.0);
2872 pipeInit(&pipe
, xStart
, yStart
,
2873 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gFalse
, gFalse
);
2874 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2875 pipeSetXY(&pipe
, xStart
, y1
);
2876 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; xx
+= 8) {
2877 alpha0
= (xShift
> 0 ? (p
[xx
/ 8] << xShift
) | (p
[xx
/ 8 + 1] >> (8 - xShift
)) : p
[xx
/ 8]);
2878 for (xx1
= 0; xx1
< 8 && xx
+ xx1
< xxLimit
; ++xx1
, ++x1
) {
2879 if (state
->clip
->test(x1
, y1
)) {
2880 if (alpha0
& 0x80) {
2881 (this->*pipe
.run
)(&pipe
);
2899 SplashError
Splash::fillImageMask(SplashImageMaskSource src
, void *srcData
,
2900 int w
, int h
, SplashCoord
*mat
,
2902 SplashBitmap
*scaledMask
;
2903 SplashClipResult clipRes
;
2904 GBool minorAxisZero
;
2905 int x0
, y0
, x1
, y1
, scaledWidth
, scaledHeight
;
2909 printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2910 w
, h
, (double)mat
[0], (double)mat
[1], (double)mat
[2],
2911 (double)mat
[3], (double)mat
[4], (double)mat
[5]);
2914 if (w
== 0 && h
== 0) return splashErrZeroImage
;
2916 // check for singular matrix
2917 if (!splashCheckDet(mat
[0], mat
[1], mat
[2], mat
[3], 0.000001)) {
2918 return splashErrSingularMatrix
;
2921 minorAxisZero
= mat
[1] == 0 && mat
[2] == 0;
2924 if (mat
[0] > 0 && minorAxisZero
&& mat
[3] > 0) {
2925 x0
= imgCoordMungeLowerC(mat
[4], glyphMode
);
2926 y0
= imgCoordMungeLowerC(mat
[5], glyphMode
);
2927 x1
= imgCoordMungeUpperC(mat
[0] + mat
[4], glyphMode
);
2928 y1
= imgCoordMungeUpperC(mat
[3] + mat
[5], glyphMode
);
2929 // make sure narrow images cover at least one pixel
2936 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
2937 opClipRes
= clipRes
;
2938 if (clipRes
!= splashClipAllOutside
) {
2939 scaledWidth
= x1
- x0
;
2940 scaledHeight
= y1
- y0
;
2941 yp
= h
/ scaledHeight
;
2942 if (yp
< 0 || yp
> INT_MAX
- 1) {
2943 return splashErrBadArg
;
2945 scaledMask
= scaleMask(src
, srcData
, w
, h
, scaledWidth
, scaledHeight
);
2946 blitMask(scaledMask
, x0
, y0
, clipRes
);
2950 // scaling plus vertical flip
2951 } else if (mat
[0] > 0 && minorAxisZero
&& mat
[3] < 0) {
2952 x0
= imgCoordMungeLowerC(mat
[4], glyphMode
);
2953 y0
= imgCoordMungeLowerC(mat
[3] + mat
[5], glyphMode
);
2954 x1
= imgCoordMungeUpperC(mat
[0] + mat
[4], glyphMode
);
2955 y1
= imgCoordMungeUpperC(mat
[5], glyphMode
);
2956 // make sure narrow images cover at least one pixel
2963 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
2964 opClipRes
= clipRes
;
2965 if (clipRes
!= splashClipAllOutside
) {
2966 scaledWidth
= x1
- x0
;
2967 scaledHeight
= y1
- y0
;
2968 yp
= h
/ scaledHeight
;
2969 if (yp
< 0 || yp
> INT_MAX
- 1) {
2970 return splashErrBadArg
;
2972 scaledMask
= scaleMask(src
, srcData
, w
, h
, scaledWidth
, scaledHeight
);
2973 vertFlipImage(scaledMask
, scaledWidth
, scaledHeight
, 1);
2974 blitMask(scaledMask
, x0
, y0
, clipRes
);
2980 arbitraryTransformMask(src
, srcData
, w
, h
, mat
, glyphMode
);
2986 void Splash::arbitraryTransformMask(SplashImageMaskSource src
, void *srcData
,
2987 int srcWidth
, int srcHeight
,
2988 SplashCoord
*mat
, GBool glyphMode
) {
2989 SplashBitmap
*scaledMask
;
2990 SplashClipResult clipRes
, clipRes2
;
2992 int scaledWidth
, scaledHeight
, t0
, t1
;
2993 SplashCoord r00
, r01
, r10
, r11
, det
, ir00
, ir01
, ir10
, ir11
;
2994 SplashCoord vx
[4], vy
[4];
2995 int xMin
, yMin
, xMax
, yMax
;
2996 ImageSection section
[3];
2998 int y
, xa
, xb
, x
, i
, xx
, yy
;
3000 // compute the four vertices of the target quadrilateral
3001 vx
[0] = mat
[4]; vy
[0] = mat
[5];
3002 vx
[1] = mat
[2] + mat
[4]; vy
[1] = mat
[3] + mat
[5];
3003 vx
[2] = mat
[0] + mat
[2] + mat
[4]; vy
[2] = mat
[1] + mat
[3] + mat
[5];
3004 vx
[3] = mat
[0] + mat
[4]; vy
[3] = mat
[1] + mat
[5];
3007 xMin
= imgCoordMungeLowerC(vx
[0], glyphMode
);
3008 xMax
= imgCoordMungeUpperC(vx
[0], glyphMode
);
3009 yMin
= imgCoordMungeLowerC(vy
[0], glyphMode
);
3010 yMax
= imgCoordMungeUpperC(vy
[0], glyphMode
);
3011 for (i
= 1; i
< 4; ++i
) {
3012 t0
= imgCoordMungeLowerC(vx
[i
], glyphMode
);
3016 t0
= imgCoordMungeUpperC(vx
[i
], glyphMode
);
3020 t1
= imgCoordMungeLowerC(vy
[i
], glyphMode
);
3024 t1
= imgCoordMungeUpperC(vy
[i
], glyphMode
);
3029 clipRes
= state
->clip
->testRect(xMin
, yMin
, xMax
- 1, yMax
- 1);
3030 opClipRes
= clipRes
;
3031 if (clipRes
== splashClipAllOutside
) {
3035 // compute the scale factors
3037 t0
= imgCoordMungeUpperC(mat
[0] + mat
[4], glyphMode
) -
3038 imgCoordMungeLowerC(mat
[4], glyphMode
);
3040 t0
= imgCoordMungeUpperC(mat
[4], glyphMode
) -
3041 imgCoordMungeLowerC(mat
[0] + mat
[4], glyphMode
);
3044 t1
= imgCoordMungeUpperC(mat
[1] + mat
[5], glyphMode
) -
3045 imgCoordMungeLowerC(mat
[5], glyphMode
);
3047 t1
= imgCoordMungeUpperC(mat
[5], glyphMode
) -
3048 imgCoordMungeLowerC(mat
[1] + mat
[5], glyphMode
);
3050 scaledWidth
= t0
> t1
? t0
: t1
;
3052 t0
= imgCoordMungeUpperC(mat
[2] + mat
[4], glyphMode
) -
3053 imgCoordMungeLowerC(mat
[4], glyphMode
);
3055 t0
= imgCoordMungeUpperC(mat
[4], glyphMode
) -
3056 imgCoordMungeLowerC(mat
[2] + mat
[4], glyphMode
);
3059 t1
= imgCoordMungeUpperC(mat
[3] + mat
[5], glyphMode
) -
3060 imgCoordMungeLowerC(mat
[5], glyphMode
);
3062 t1
= imgCoordMungeUpperC(mat
[5], glyphMode
) -
3063 imgCoordMungeLowerC(mat
[3] + mat
[5], glyphMode
);
3065 scaledHeight
= t0
> t1
? t0
: t1
;
3066 if (scaledWidth
== 0) {
3069 if (scaledHeight
== 0) {
3073 // compute the inverse transform (after scaling) matrix
3074 r00
= mat
[0] / scaledWidth
;
3075 r01
= mat
[1] / scaledWidth
;
3076 r10
= mat
[2] / scaledHeight
;
3077 r11
= mat
[3] / scaledHeight
;
3078 det
= r00
* r11
- r01
* r10
;
3079 if (splashAbs(det
) < 1e-6) {
3080 // this should be caught by the singular matrix check in fillImageMask
3088 // scale the input image
3089 scaledMask
= scaleMask(src
, srcData
, srcWidth
, srcHeight
,
3090 scaledWidth
, scaledHeight
);
3091 if (scaledMask
->data
== NULL
) {
3092 error(errInternal
, -1, "scaledMask->data is NULL in Splash::arbitraryTransformMask");
3097 // construct the three sections
3098 i
= (vy
[2] <= vy
[3]) ? 2 : 3;
3099 if (vy
[1] <= vy
[i
]) {
3102 if (vy
[0] < vy
[i
] || (i
!= 3 && vy
[0] == vy
[i
])) {
3105 if (vy
[i
] == vy
[(i
+1) & 3]) {
3106 section
[0].y0
= imgCoordMungeLowerC(vy
[i
], glyphMode
);
3107 section
[0].y1
= imgCoordMungeUpperC(vy
[(i
+2) & 3], glyphMode
) - 1;
3108 if (vx
[i
] < vx
[(i
+1) & 3]) {
3110 section
[0].ia1
= (i
+3) & 3;
3111 section
[0].ib0
= (i
+1) & 3;
3112 section
[0].ib1
= (i
+2) & 3;
3114 section
[0].ia0
= (i
+1) & 3;
3115 section
[0].ia1
= (i
+2) & 3;
3117 section
[0].ib1
= (i
+3) & 3;
3121 section
[0].y0
= imgCoordMungeLowerC(vy
[i
], glyphMode
);
3122 section
[2].y1
= imgCoordMungeUpperC(vy
[(i
+2) & 3], glyphMode
) - 1;
3123 section
[0].ia0
= section
[0].ib0
= i
;
3124 section
[2].ia1
= section
[2].ib1
= (i
+2) & 3;
3125 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3126 section
[0].ia1
= section
[2].ia0
= (i
+1) & 3;
3127 section
[0].ib1
= section
[2].ib0
= (i
+3) & 3;
3129 section
[0].ia1
= section
[2].ia0
= (i
+3) & 3;
3130 section
[0].ib1
= section
[2].ib0
= (i
+1) & 3;
3132 if (vy
[(i
+1) & 3] < vy
[(i
+3) & 3]) {
3133 section
[1].y0
= imgCoordMungeLowerC(vy
[(i
+1) & 3], glyphMode
);
3134 section
[2].y0
= imgCoordMungeUpperC(vy
[(i
+3) & 3], glyphMode
);
3135 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3136 section
[1].ia0
= (i
+1) & 3;
3137 section
[1].ia1
= (i
+2) & 3;
3139 section
[1].ib1
= (i
+3) & 3;
3142 section
[1].ia1
= (i
+3) & 3;
3143 section
[1].ib0
= (i
+1) & 3;
3144 section
[1].ib1
= (i
+2) & 3;
3147 section
[1].y0
= imgCoordMungeLowerC(vy
[(i
+3) & 3], glyphMode
);
3148 section
[2].y0
= imgCoordMungeUpperC(vy
[(i
+1) & 3], glyphMode
);
3149 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3151 section
[1].ia1
= (i
+1) & 3;
3152 section
[1].ib0
= (i
+3) & 3;
3153 section
[1].ib1
= (i
+2) & 3;
3155 section
[1].ia0
= (i
+3) & 3;
3156 section
[1].ia1
= (i
+2) & 3;
3158 section
[1].ib1
= (i
+1) & 3;
3161 section
[0].y1
= section
[1].y0
- 1;
3162 section
[1].y1
= section
[2].y0
- 1;
3165 for (i
= 0; i
< nSections
; ++i
) {
3166 section
[i
].xa0
= vx
[section
[i
].ia0
];
3167 section
[i
].ya0
= vy
[section
[i
].ia0
];
3168 section
[i
].xa1
= vx
[section
[i
].ia1
];
3169 section
[i
].ya1
= vy
[section
[i
].ia1
];
3170 section
[i
].xb0
= vx
[section
[i
].ib0
];
3171 section
[i
].yb0
= vy
[section
[i
].ib0
];
3172 section
[i
].xb1
= vx
[section
[i
].ib1
];
3173 section
[i
].yb1
= vy
[section
[i
].ib1
];
3174 section
[i
].dxdya
= (section
[i
].xa1
- section
[i
].xa0
) /
3175 (section
[i
].ya1
- section
[i
].ya0
);
3176 section
[i
].dxdyb
= (section
[i
].xb1
- section
[i
].xb0
) /
3177 (section
[i
].yb1
- section
[i
].yb0
);
3180 // initialize the pixel pipe
3181 pipeInit(&pipe
, 0, 0, state
->fillPattern
, NULL
,
3182 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
3183 if (vectorAntialias
) {
3187 // make sure narrow images cover at least one pixel
3188 if (nSections
== 1) {
3189 if (section
[0].y0
== section
[0].y1
) {
3191 clipRes
= opClipRes
= splashClipPartial
;
3194 if (section
[0].y0
== section
[2].y1
) {
3196 clipRes
= opClipRes
= splashClipPartial
;
3200 // scan all pixels inside the target region
3201 for (i
= 0; i
< nSections
; ++i
) {
3202 for (y
= section
[i
].y0
; y
<= section
[i
].y1
; ++y
) {
3203 xa
= imgCoordMungeLowerC(section
[i
].xa0
+
3204 ((SplashCoord
)y
+ 0.5 - section
[i
].ya0
) *
3207 xb
= imgCoordMungeUpperC(section
[i
].xb0
+
3208 ((SplashCoord
)y
+ 0.5 - section
[i
].yb0
) *
3211 if (unlikely(xa
< 0))
3213 // make sure narrow images cover at least one pixel
3217 if (clipRes
!= splashClipAllInside
) {
3218 clipRes2
= state
->clip
->testSpan(xa
, xb
- 1, y
);
3222 for (x
= xa
; x
< xb
; ++x
) {
3223 // map (x+0.5, y+0.5) back to the scaled image
3224 xx
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir00
+
3225 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir10
);
3226 yy
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir01
+
3227 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir11
);
3228 // xx should always be within bounds, but floating point
3229 // inaccuracy can cause problems
3232 } else if (xx
>= scaledWidth
) {
3233 xx
= scaledWidth
- 1;
3237 } else if (yy
>= scaledHeight
) {
3238 yy
= scaledHeight
- 1;
3240 pipe
.shape
= scaledMask
->data
[yy
* scaledWidth
+ xx
];
3241 if (vectorAntialias
&& clipRes2
!= splashClipAllInside
) {
3242 drawAAPixel(&pipe
, x
, y
);
3244 drawPixel(&pipe
, x
, y
, clipRes2
== splashClipAllInside
);
3253 // Scale an image mask into a SplashBitmap.
3254 SplashBitmap
*Splash::scaleMask(SplashImageMaskSource src
, void *srcData
,
3255 int srcWidth
, int srcHeight
,
3256 int scaledWidth
, int scaledHeight
) {
3259 dest
= new SplashBitmap(scaledWidth
, scaledHeight
, 1, splashModeMono8
,
3261 if (scaledHeight
< srcHeight
) {
3262 if (scaledWidth
< srcWidth
) {
3263 scaleMaskYdXd(src
, srcData
, srcWidth
, srcHeight
,
3264 scaledWidth
, scaledHeight
, dest
);
3266 scaleMaskYdXu(src
, srcData
, srcWidth
, srcHeight
,
3267 scaledWidth
, scaledHeight
, dest
);
3270 if (scaledWidth
< srcWidth
) {
3271 scaleMaskYuXd(src
, srcData
, srcWidth
, srcHeight
,
3272 scaledWidth
, scaledHeight
, dest
);
3274 scaleMaskYuXu(src
, srcData
, srcWidth
, srcHeight
,
3275 scaledWidth
, scaledHeight
, dest
);
3281 void Splash::scaleMaskYdXd(SplashImageMaskSource src
, void *srcData
,
3282 int srcWidth
, int srcHeight
,
3283 int scaledWidth
, int scaledHeight
,
3284 SplashBitmap
*dest
) {
3289 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, d
, d0
, d1
;
3292 // Bresenham parameters for y scale
3293 yp
= srcHeight
/ scaledHeight
;
3294 yq
= srcHeight
% scaledHeight
;
3296 // Bresenham parameters for x scale
3297 xp
= srcWidth
/ scaledWidth
;
3298 xq
= srcWidth
% scaledWidth
;
3301 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3302 pixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
3304 // init y scale Bresenham
3307 destPtr
= dest
->data
;
3308 for (y
= 0; y
< scaledHeight
; ++y
) {
3310 // y scale Bresenham
3311 if ((yt
+= yq
) >= scaledHeight
) {
3318 // read rows from image
3319 memset(pixBuf
, 0, srcWidth
* sizeof(int));
3320 for (i
= 0; i
< yStep
; ++i
) {
3321 (*src
)(srcData
, lineBuf
);
3322 for (j
= 0; j
< srcWidth
; ++j
) {
3323 pixBuf
[j
] += lineBuf
[j
];
3327 // init x scale Bresenham
3329 d0
= (255 << 23) / (yStep
* xp
);
3330 d1
= (255 << 23) / (yStep
* (xp
+ 1));
3333 for (x
= 0; x
< scaledWidth
; ++x
) {
3335 // x scale Bresenham
3336 if ((xt
+= xq
) >= scaledWidth
) {
3345 // compute the final pixel
3347 for (i
= 0; i
< xStep
; ++i
) {
3348 pix
+= pixBuf
[xx
++];
3350 // (255 * pix) / xStep * yStep
3351 pix
= (pix
* d
) >> 23;
3354 *destPtr
++ = (Guchar
)pix
;
3362 void Splash::scaleMaskYdXu(SplashImageMaskSource src
, void *srcData
,
3363 int srcWidth
, int srcHeight
,
3364 int scaledWidth
, int scaledHeight
,
3365 SplashBitmap
*dest
) {
3370 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, d
;
3373 destPtr
= dest
->data
;
3374 if (destPtr
== NULL
) {
3375 error(errInternal
, -1, "dest->data is NULL in Splash::scaleMaskYdXu");
3379 // Bresenham parameters for y scale
3380 yp
= srcHeight
/ scaledHeight
;
3381 yq
= srcHeight
% scaledHeight
;
3383 // Bresenham parameters for x scale
3384 xp
= scaledWidth
/ srcWidth
;
3385 xq
= scaledWidth
% srcWidth
;
3388 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3389 pixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
3391 // init y scale Bresenham
3394 for (y
= 0; y
< scaledHeight
; ++y
) {
3396 // y scale Bresenham
3397 if ((yt
+= yq
) >= scaledHeight
) {
3404 // read rows from image
3405 memset(pixBuf
, 0, srcWidth
* sizeof(int));
3406 for (i
= 0; i
< yStep
; ++i
) {
3407 (*src
)(srcData
, lineBuf
);
3408 for (j
= 0; j
< srcWidth
; ++j
) {
3409 pixBuf
[j
] += lineBuf
[j
];
3413 // init x scale Bresenham
3415 d
= (255 << 23) / yStep
;
3417 for (x
= 0; x
< srcWidth
; ++x
) {
3419 // x scale Bresenham
3420 if ((xt
+= xq
) >= srcWidth
) {
3427 // compute the final pixel
3429 // (255 * pix) / yStep
3430 pix
= (pix
* d
) >> 23;
3433 for (i
= 0; i
< xStep
; ++i
) {
3434 *destPtr
++ = (Guchar
)pix
;
3443 void Splash::scaleMaskYuXd(SplashImageMaskSource src
, void *srcData
,
3444 int srcWidth
, int srcHeight
,
3445 int scaledWidth
, int scaledHeight
,
3446 SplashBitmap
*dest
) {
3449 Guchar
*destPtr0
, *destPtr
;
3450 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, d
, d0
, d1
;
3453 destPtr0
= dest
->data
;
3454 if (destPtr0
== NULL
) {
3455 error(errInternal
, -1, "dest->data is NULL in Splash::scaleMaskYuXd");
3459 // Bresenham parameters for y scale
3460 yp
= scaledHeight
/ srcHeight
;
3461 yq
= scaledHeight
% srcHeight
;
3463 // Bresenham parameters for x scale
3464 xp
= srcWidth
/ scaledWidth
;
3465 xq
= srcWidth
% scaledWidth
;
3468 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3470 // init y scale Bresenham
3473 for (y
= 0; y
< srcHeight
; ++y
) {
3475 // y scale Bresenham
3476 if ((yt
+= yq
) >= srcHeight
) {
3483 // read row from image
3484 (*src
)(srcData
, lineBuf
);
3486 // init x scale Bresenham
3488 d0
= (255 << 23) / xp
;
3489 d1
= (255 << 23) / (xp
+ 1);
3492 for (x
= 0; x
< scaledWidth
; ++x
) {
3494 // x scale Bresenham
3495 if ((xt
+= xq
) >= scaledWidth
) {
3504 // compute the final pixel
3506 for (i
= 0; i
< xStep
; ++i
) {
3507 pix
+= lineBuf
[xx
++];
3509 // (255 * pix) / xStep
3510 pix
= (pix
* d
) >> 23;
3513 for (i
= 0; i
< yStep
; ++i
) {
3514 destPtr
= destPtr0
+ i
* scaledWidth
+ x
;
3515 *destPtr
= (Guchar
)pix
;
3519 destPtr0
+= yStep
* scaledWidth
;
3525 void Splash::scaleMaskYuXu(SplashImageMaskSource src
, void *srcData
,
3526 int srcWidth
, int srcHeight
,
3527 int scaledWidth
, int scaledHeight
,
3528 SplashBitmap
*dest
) {
3531 Guchar
*destPtr0
, *destPtr
;
3532 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
;
3535 destPtr0
= dest
->data
;
3536 if (destPtr0
== NULL
) {
3537 error(errInternal
, -1, "dest->data is NULL in Splash::scaleMaskYuXu");
3541 // Bresenham parameters for y scale
3542 yp
= scaledHeight
/ srcHeight
;
3543 yq
= scaledHeight
% srcHeight
;
3545 // Bresenham parameters for x scale
3546 xp
= scaledWidth
/ srcWidth
;
3547 xq
= scaledWidth
% srcWidth
;
3550 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3552 // init y scale Bresenham
3555 for (y
= 0; y
< srcHeight
; ++y
) {
3557 // y scale Bresenham
3558 if ((yt
+= yq
) >= srcHeight
) {
3565 // read row from image
3566 (*src
)(srcData
, lineBuf
);
3568 // init x scale Bresenham
3572 for (x
= 0; x
< srcWidth
; ++x
) {
3574 // x scale Bresenham
3575 if ((xt
+= xq
) >= srcWidth
) {
3582 // compute the final pixel
3583 pix
= lineBuf
[x
] ? 255 : 0;
3586 for (i
= 0; i
< yStep
; ++i
) {
3587 for (j
= 0; j
< xStep
; ++j
) {
3588 destPtr
= destPtr0
+ i
* scaledWidth
+ xx
+ j
;
3589 *destPtr
++ = (Guchar
)pix
;
3596 destPtr0
+= yStep
* scaledWidth
;
3602 void Splash::blitMask(SplashBitmap
*src
, int xDest
, int yDest
,
3603 SplashClipResult clipRes
) {
3608 w
= src
->getWidth();
3609 h
= src
->getHeight();
3610 p
= src
->getDataPtr();
3612 error(errInternal
, -1, "src->getDataPtr() is NULL in Splash::blitMask");
3615 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
3616 pipeInit(&pipe
, xDest
, yDest
, state
->fillPattern
, NULL
,
3617 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
3619 for (y
= 0; y
< h
; ++y
) {
3620 for (x
= 0; x
< w
; ++x
) {
3622 drawAAPixel(&pipe
, xDest
+ x
, yDest
+ y
);
3626 pipeInit(&pipe
, xDest
, yDest
, state
->fillPattern
, NULL
,
3627 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
3628 if (clipRes
== splashClipAllInside
) {
3629 for (y
= 0; y
< h
; ++y
) {
3630 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
3631 for (x
= 0; x
< w
; ++x
) {
3634 (this->*pipe
.run
)(&pipe
);
3642 updateModX(xDest
+ w
- 1);
3644 updateModY(yDest
+ h
- 1);
3646 for (y
= 0; y
< h
; ++y
) {
3647 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
3648 for (x
= 0; x
< w
; ++x
) {
3649 if (*p
&& state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
3651 (this->*pipe
.run
)(&pipe
);
3652 updateModX(xDest
+ x
);
3653 updateModY(yDest
+ y
);
3664 SplashError
Splash::drawImage(SplashImageSource src
, SplashICCTransform tf
, void *srcData
,
3665 SplashColorMode srcMode
, GBool srcAlpha
,
3666 int w
, int h
, SplashCoord
*mat
, GBool interpolate
,
3667 GBool tilingPattern
) {
3669 SplashBitmap
*scaledImg
;
3670 SplashClipResult clipRes
;
3671 GBool minorAxisZero
;
3672 int x0
, y0
, x1
, y1
, scaledWidth
, scaledHeight
;
3677 printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
3678 srcMode
, srcAlpha
, w
, h
, (double)mat
[0], (double)mat
[1], (double)mat
[2],
3679 (double)mat
[3], (double)mat
[4], (double)mat
[5]);
3682 // check color modes
3683 ok
= gFalse
; // make gcc happy
3684 nComps
= 0; // make gcc happy
3685 switch (bitmap
->mode
) {
3686 case splashModeMono1
:
3687 case splashModeMono8
:
3688 ok
= srcMode
== splashModeMono8
;
3691 case splashModeRGB8
:
3692 ok
= srcMode
== splashModeRGB8
;
3695 case splashModeXBGR8
:
3696 ok
= srcMode
== splashModeXBGR8
;
3699 case splashModeBGR8
:
3700 ok
= srcMode
== splashModeBGR8
;
3704 case splashModeCMYK8
:
3705 ok
= srcMode
== splashModeCMYK8
;
3708 case splashModeDeviceN8
:
3709 ok
= srcMode
== splashModeDeviceN8
;
3710 nComps
= SPOT_NCOMPS
+4;
3718 return splashErrModeMismatch
;
3721 // check for singular matrix
3722 if (!splashCheckDet(mat
[0], mat
[1], mat
[2], mat
[3], 0.000001)) {
3723 return splashErrSingularMatrix
;
3726 minorAxisZero
= mat
[1] == 0 && mat
[2] == 0;
3729 if (mat
[0] > 0 && minorAxisZero
&& mat
[3] > 0) {
3730 x0
= imgCoordMungeLower(mat
[4]);
3731 y0
= imgCoordMungeLower(mat
[5]);
3732 x1
= imgCoordMungeUpper(mat
[0] + mat
[4]);
3733 y1
= imgCoordMungeUpper(mat
[3] + mat
[5]);
3734 // make sure narrow images cover at least one pixel
3741 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
3742 opClipRes
= clipRes
;
3743 if (clipRes
!= splashClipAllOutside
) {
3744 scaledWidth
= x1
- x0
;
3745 scaledHeight
= y1
- y0
;
3746 yp
= h
/ scaledHeight
;
3747 if (yp
< 0 || yp
> INT_MAX
- 1) {
3748 return splashErrBadArg
;
3750 scaledImg
= scaleImage(src
, srcData
, srcMode
, nComps
, srcAlpha
, w
, h
,
3751 scaledWidth
, scaledHeight
, interpolate
, tilingPattern
);
3752 if (scaledImg
== NULL
) {
3753 return splashErrBadArg
;
3756 (*tf
)(srcData
, scaledImg
);
3758 blitImage(scaledImg
, srcAlpha
, x0
, y0
, clipRes
);
3762 // scaling plus vertical flip
3763 } else if (mat
[0] > 0 && minorAxisZero
&& mat
[3] < 0) {
3764 x0
= imgCoordMungeLower(mat
[4]);
3765 y0
= imgCoordMungeLower(mat
[3] + mat
[5]);
3766 x1
= imgCoordMungeUpper(mat
[0] + mat
[4]);
3767 y1
= imgCoordMungeUpper(mat
[5]);
3769 if (mat
[4] + mat
[0] * 0.5 < x0
) {
3776 if (mat
[5] + mat
[1] * 0.5 < y0
) {
3782 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
3783 opClipRes
= clipRes
;
3784 if (clipRes
!= splashClipAllOutside
) {
3785 scaledWidth
= x1
- x0
;
3786 scaledHeight
= y1
- y0
;
3787 yp
= h
/ scaledHeight
;
3788 if (yp
< 0 || yp
> INT_MAX
- 1) {
3789 return splashErrBadArg
;
3791 scaledImg
= scaleImage(src
, srcData
, srcMode
, nComps
, srcAlpha
, w
, h
,
3792 scaledWidth
, scaledHeight
, interpolate
, tilingPattern
);
3793 if (scaledImg
== NULL
) {
3794 return splashErrBadArg
;
3797 (*tf
)(srcData
, scaledImg
);
3799 vertFlipImage(scaledImg
, scaledWidth
, scaledHeight
, nComps
);
3800 blitImage(scaledImg
, srcAlpha
, x0
, y0
, clipRes
);
3806 return arbitraryTransformImage(src
, tf
, srcData
, srcMode
, nComps
, srcAlpha
,
3807 w
, h
, mat
, interpolate
, tilingPattern
);
3813 SplashError
Splash::arbitraryTransformImage(SplashImageSource src
, SplashICCTransform tf
, void *srcData
,
3814 SplashColorMode srcMode
, int nComps
,
3816 int srcWidth
, int srcHeight
,
3817 SplashCoord
*mat
, GBool interpolate
,
3818 GBool tilingPattern
) {
3819 SplashBitmap
*scaledImg
;
3820 SplashClipResult clipRes
, clipRes2
;
3823 int scaledWidth
, scaledHeight
, t0
, t1
, th
;
3824 SplashCoord r00
, r01
, r10
, r11
, det
, ir00
, ir01
, ir10
, ir11
;
3825 SplashCoord vx
[4], vy
[4];
3826 int xMin
, yMin
, xMax
, yMax
;
3827 ImageSection section
[3];
3829 int y
, xa
, xb
, x
, i
, xx
, yy
, yp
;
3831 // compute the four vertices of the target quadrilateral
3832 vx
[0] = mat
[4]; vy
[0] = mat
[5];
3833 vx
[1] = mat
[2] + mat
[4]; vy
[1] = mat
[3] + mat
[5];
3834 vx
[2] = mat
[0] + mat
[2] + mat
[4]; vy
[2] = mat
[1] + mat
[3] + mat
[5];
3835 vx
[3] = mat
[0] + mat
[4]; vy
[3] = mat
[1] + mat
[5];
3838 xMin
= imgCoordMungeLower(vx
[0]);
3839 xMax
= imgCoordMungeUpper(vx
[0]);
3840 yMin
= imgCoordMungeLower(vy
[0]);
3841 yMax
= imgCoordMungeUpper(vy
[0]);
3842 for (i
= 1; i
< 4; ++i
) {
3843 t0
= imgCoordMungeLower(vx
[i
]);
3847 t0
= imgCoordMungeUpper(vx
[i
]);
3851 t1
= imgCoordMungeLower(vy
[i
]);
3855 t1
= imgCoordMungeUpper(vy
[i
]);
3860 clipRes
= state
->clip
->testRect(xMin
, yMin
, xMax
, yMax
);
3861 opClipRes
= clipRes
;
3862 if (clipRes
== splashClipAllOutside
) {
3866 // compute the scale factors
3867 if (splashAbs(mat
[0]) >= splashAbs(mat
[1])) {
3868 scaledWidth
= xMax
- xMin
;
3869 scaledHeight
= yMax
- yMin
;
3871 scaledWidth
= yMax
- yMin
;
3872 scaledHeight
= xMax
- xMin
;
3874 if (scaledHeight
<= 1 || scaledWidth
<= 1 || tilingPattern
) {
3876 t0
= imgCoordMungeUpper(mat
[0] + mat
[4]) - imgCoordMungeLower(mat
[4]);
3878 t0
= imgCoordMungeUpper(mat
[4]) - imgCoordMungeLower(mat
[0] + mat
[4]);
3881 t1
= imgCoordMungeUpper(mat
[1] + mat
[5]) - imgCoordMungeLower(mat
[5]);
3883 t1
= imgCoordMungeUpper(mat
[5]) - imgCoordMungeLower(mat
[1] + mat
[5]);
3885 scaledWidth
= t0
> t1
? t0
: t1
;
3887 t0
= imgCoordMungeUpper(mat
[2] + mat
[4]) - imgCoordMungeLower(mat
[4]);
3888 if (splashAbs(mat
[1]) >= 1) {
3889 th
= imgCoordMungeUpper(mat
[2]) - imgCoordMungeLower(mat
[0] * mat
[3] / mat
[1]);
3890 if (th
> t0
) t0
= th
;
3893 t0
= imgCoordMungeUpper(mat
[4]) - imgCoordMungeLower(mat
[2] + mat
[4]);
3894 if (splashAbs(mat
[1]) >= 1) {
3895 th
= imgCoordMungeUpper(mat
[0] * mat
[3] / mat
[1]) - imgCoordMungeLower(mat
[2]);
3896 if (th
> t0
) t0
= th
;
3900 t1
= imgCoordMungeUpper(mat
[3] + mat
[5]) - imgCoordMungeLower(mat
[5]);
3901 if (splashAbs(mat
[0]) >= 1) {
3902 th
= imgCoordMungeUpper(mat
[3]) - imgCoordMungeLower(mat
[1] * mat
[2] / mat
[0]);
3903 if (th
> t1
) t1
= th
;
3906 t1
= imgCoordMungeUpper(mat
[5]) - imgCoordMungeLower(mat
[3] + mat
[5]);
3907 if (splashAbs(mat
[0]) >= 1) {
3908 th
= imgCoordMungeUpper(mat
[1] * mat
[2] / mat
[0]) - imgCoordMungeLower(mat
[3]);
3909 if (th
> t1
) t1
= th
;
3912 scaledHeight
= t0
> t1
? t0
: t1
;
3914 if (scaledWidth
== 0) {
3917 if (scaledHeight
== 0) {
3921 // compute the inverse transform (after scaling) matrix
3922 r00
= mat
[0] / scaledWidth
;
3923 r01
= mat
[1] / scaledWidth
;
3924 r10
= mat
[2] / scaledHeight
;
3925 r11
= mat
[3] / scaledHeight
;
3926 det
= r00
* r11
- r01
* r10
;
3927 if (splashAbs(det
) < 1e-6) {
3928 // this should be caught by the singular matrix check in drawImage
3929 return splashErrBadArg
;
3936 // scale the input image
3937 yp
= srcHeight
/ scaledHeight
;
3938 if (yp
< 0 || yp
> INT_MAX
- 1) {
3939 return splashErrBadArg
;
3941 scaledImg
= scaleImage(src
, srcData
, srcMode
, nComps
, srcAlpha
,
3942 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, interpolate
);
3944 if (scaledImg
== NULL
) {
3945 return splashErrBadArg
;
3949 (*tf
)(srcData
, scaledImg
);
3951 // construct the three sections
3953 if (vy
[1] < vy
[i
]) {
3956 if (vy
[2] < vy
[i
]) {
3959 if (vy
[3] < vy
[i
]) {
3962 // NB: if using fixed point, 0.000001 will be truncated to zero,
3963 // so these two comparisons must be <=, not <
3964 if (splashAbs(vy
[i
] - vy
[(i
-1) & 3]) <= 0.000001 &&
3965 vy
[(i
-1) & 3] < vy
[(i
+1) & 3]) {
3968 if (splashAbs(vy
[i
] - vy
[(i
+1) & 3]) <= 0.000001) {
3969 section
[0].y0
= imgCoordMungeLower(vy
[i
]);
3970 section
[0].y1
= imgCoordMungeUpper(vy
[(i
+2) & 3]) - 1;
3971 if (vx
[i
] < vx
[(i
+1) & 3]) {
3973 section
[0].ia1
= (i
+3) & 3;
3974 section
[0].ib0
= (i
+1) & 3;
3975 section
[0].ib1
= (i
+2) & 3;
3977 section
[0].ia0
= (i
+1) & 3;
3978 section
[0].ia1
= (i
+2) & 3;
3980 section
[0].ib1
= (i
+3) & 3;
3984 section
[0].y0
= imgCoordMungeLower(vy
[i
]);
3985 section
[2].y1
= imgCoordMungeUpper(vy
[(i
+2) & 3]) - 1;
3986 section
[0].ia0
= section
[0].ib0
= i
;
3987 section
[2].ia1
= section
[2].ib1
= (i
+2) & 3;
3988 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3989 section
[0].ia1
= section
[2].ia0
= (i
+1) & 3;
3990 section
[0].ib1
= section
[2].ib0
= (i
+3) & 3;
3992 section
[0].ia1
= section
[2].ia0
= (i
+3) & 3;
3993 section
[0].ib1
= section
[2].ib0
= (i
+1) & 3;
3995 if (vy
[(i
+1) & 3] < vy
[(i
+3) & 3]) {
3996 section
[1].y0
= imgCoordMungeLower(vy
[(i
+1) & 3]);
3997 section
[2].y0
= imgCoordMungeUpper(vy
[(i
+3) & 3]);
3998 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3999 section
[1].ia0
= (i
+1) & 3;
4000 section
[1].ia1
= (i
+2) & 3;
4002 section
[1].ib1
= (i
+3) & 3;
4005 section
[1].ia1
= (i
+3) & 3;
4006 section
[1].ib0
= (i
+1) & 3;
4007 section
[1].ib1
= (i
+2) & 3;
4010 section
[1].y0
= imgCoordMungeLower(vy
[(i
+3) & 3]);
4011 section
[2].y0
= imgCoordMungeUpper(vy
[(i
+1) & 3]);
4012 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
4014 section
[1].ia1
= (i
+1) & 3;
4015 section
[1].ib0
= (i
+3) & 3;
4016 section
[1].ib1
= (i
+2) & 3;
4018 section
[1].ia0
= (i
+3) & 3;
4019 section
[1].ia1
= (i
+2) & 3;
4021 section
[1].ib1
= (i
+1) & 3;
4024 section
[0].y1
= section
[1].y0
- 1;
4025 section
[1].y1
= section
[2].y0
- 1;
4028 for (i
= 0; i
< nSections
; ++i
) {
4029 section
[i
].xa0
= vx
[section
[i
].ia0
];
4030 section
[i
].ya0
= vy
[section
[i
].ia0
];
4031 section
[i
].xa1
= vx
[section
[i
].ia1
];
4032 section
[i
].ya1
= vy
[section
[i
].ia1
];
4033 section
[i
].xb0
= vx
[section
[i
].ib0
];
4034 section
[i
].yb0
= vy
[section
[i
].ib0
];
4035 section
[i
].xb1
= vx
[section
[i
].ib1
];
4036 section
[i
].yb1
= vy
[section
[i
].ib1
];
4037 section
[i
].dxdya
= (section
[i
].xa1
- section
[i
].xa0
) /
4038 (section
[i
].ya1
- section
[i
].ya0
);
4039 section
[i
].dxdyb
= (section
[i
].xb1
- section
[i
].xb0
) /
4040 (section
[i
].yb1
- section
[i
].yb0
);
4043 // initialize the pixel pipe
4044 pipeInit(&pipe
, 0, 0, NULL
, pixel
,
4045 (Guchar
)splashRound(state
->fillAlpha
* 255),
4046 srcAlpha
|| (vectorAntialias
&& clipRes
!= splashClipAllInside
),
4048 if (vectorAntialias
) {
4052 // make sure narrow images cover at least one pixel
4053 if (nSections
== 1) {
4054 if (section
[0].y0
== section
[0].y1
) {
4056 clipRes
= opClipRes
= splashClipPartial
;
4059 if (section
[0].y0
== section
[2].y1
) {
4061 clipRes
= opClipRes
= splashClipPartial
;
4065 // scan all pixels inside the target region
4066 for (i
= 0; i
< nSections
; ++i
) {
4067 for (y
= section
[i
].y0
; y
<= section
[i
].y1
; ++y
) {
4068 xa
= imgCoordMungeLower(section
[i
].xa0
+
4069 ((SplashCoord
)y
+ 0.5 - section
[i
].ya0
) *
4071 if (unlikely(xa
< 0))
4073 xb
= imgCoordMungeUpper(section
[i
].xb0
+
4074 ((SplashCoord
)y
+ 0.5 - section
[i
].yb0
) *
4076 // make sure narrow images cover at least one pixel
4080 if (clipRes
!= splashClipAllInside
) {
4081 clipRes2
= state
->clip
->testSpan(xa
, xb
- 1, y
);
4085 for (x
= xa
; x
< xb
; ++x
) {
4086 // map (x+0.5, y+0.5) back to the scaled image
4087 xx
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir00
+
4088 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir10
);
4089 yy
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir01
+
4090 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir11
);
4091 // xx should always be within bounds, but floating point
4092 // inaccuracy can cause problems
4095 } else if (xx
>= scaledWidth
) {
4096 xx
= scaledWidth
- 1;
4100 } else if (yy
>= scaledHeight
) {
4101 yy
= scaledHeight
- 1;
4103 scaledImg
->getPixel(xx
, yy
, pixel
);
4105 pipe
.shape
= scaledImg
->alpha
[yy
* scaledWidth
+ xx
];
4109 if (vectorAntialias
&& clipRes2
!= splashClipAllInside
) {
4110 drawAAPixel(&pipe
, x
, y
);
4112 drawPixel(&pipe
, x
, y
, clipRes2
== splashClipAllInside
);
4122 // determine if a scaled image requires interpolation based on the scale and
4123 // the interpolate flag from the image dictionary
4124 static GBool
isImageInterpolationRequired(int srcWidth
, int srcHeight
,
4125 int scaledWidth
, int scaledHeight
,
4126 GBool interpolate
) {
4130 /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
4131 if (scaledWidth
/ srcWidth
>= 4 || scaledHeight
/ srcHeight
>= 4)
4137 // Scale an image into a SplashBitmap.
4138 SplashBitmap
*Splash::scaleImage(SplashImageSource src
, void *srcData
,
4139 SplashColorMode srcMode
, int nComps
,
4140 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4141 int scaledWidth
, int scaledHeight
, GBool interpolate
, GBool tilingPattern
) {
4144 dest
= new SplashBitmap(scaledWidth
, scaledHeight
, 1, srcMode
, srcAlpha
, gTrue
, bitmap
->getSeparationList());
4145 if (dest
->getDataPtr() != NULL
) {
4146 if (scaledHeight
< srcHeight
) {
4147 if (scaledWidth
< srcWidth
) {
4148 scaleImageYdXd(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4149 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4151 scaleImageYdXu(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4152 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4155 if (scaledWidth
< srcWidth
) {
4156 scaleImageYuXd(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4157 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4159 if (!tilingPattern
&& isImageInterpolationRequired(srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, interpolate
)) {
4160 scaleImageYuXuBilinear(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4161 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4163 scaleImageYuXu(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4164 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4175 void Splash::scaleImageYdXd(SplashImageSource src
, void *srcData
,
4176 SplashColorMode srcMode
, int nComps
,
4177 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4178 int scaledWidth
, int scaledHeight
,
4179 SplashBitmap
*dest
) {
4180 Guchar
*lineBuf
, *alphaLineBuf
;
4181 Guint
*pixBuf
, *alphaPixBuf
;
4182 Guint pix0
, pix1
, pix2
;
4185 Guint pix
[SPOT_NCOMPS
+4], cp
;
4188 Guchar
*destPtr
, *destAlphaPtr
;
4189 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, xxa
, d
, d0
, d1
;
4192 // Bresenham parameters for y scale
4193 yp
= srcHeight
/ scaledHeight
;
4194 yq
= srcHeight
% scaledHeight
;
4196 // Bresenham parameters for x scale
4197 xp
= srcWidth
/ scaledWidth
;
4198 xq
= srcWidth
% scaledWidth
;
4201 lineBuf
= (Guchar
*)gmallocn(srcWidth
, nComps
);
4202 pixBuf
= (Guint
*)gmallocn(srcWidth
, nComps
* sizeof(int));
4204 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4205 alphaPixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
4207 alphaLineBuf
= NULL
;
4211 // init y scale Bresenham
4214 destPtr
= dest
->data
;
4215 destAlphaPtr
= dest
->alpha
;
4216 for (y
= 0; y
< scaledHeight
; ++y
) {
4218 // y scale Bresenham
4219 if ((yt
+= yq
) >= scaledHeight
) {
4226 // read rows from image
4227 memset(pixBuf
, 0, srcWidth
* nComps
* sizeof(int));
4229 memset(alphaPixBuf
, 0, srcWidth
* sizeof(int));
4231 for (i
= 0; i
< yStep
; ++i
) {
4232 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4233 for (j
= 0; j
< srcWidth
* nComps
; ++j
) {
4234 pixBuf
[j
] += lineBuf
[j
];
4237 for (j
= 0; j
< srcWidth
; ++j
) {
4238 alphaPixBuf
[j
] += alphaLineBuf
[j
];
4243 // init x scale Bresenham
4245 d0
= (1 << 23) / (yStep
* xp
);
4246 d1
= (1 << 23) / (yStep
* (xp
+ 1));
4249 for (x
= 0; x
< scaledWidth
; ++x
) {
4251 // x scale Bresenham
4252 if ((xt
+= xq
) >= scaledWidth
) {
4263 case splashModeMono8
:
4265 // compute the final pixel
4267 for (i
= 0; i
< xStep
; ++i
) {
4268 pix0
+= pixBuf
[xx
++];
4270 // pix / xStep * yStep
4271 pix0
= (pix0
* d
) >> 23;
4274 *destPtr
++ = (Guchar
)pix0
;
4277 case splashModeRGB8
:
4279 // compute the final pixel
4280 pix0
= pix1
= pix2
= 0;
4281 for (i
= 0; i
< xStep
; ++i
) {
4283 pix1
+= pixBuf
[xx
+1];
4284 pix2
+= pixBuf
[xx
+2];
4287 // pix / xStep * yStep
4288 pix0
= (pix0
* d
) >> 23;
4289 pix1
= (pix1
* d
) >> 23;
4290 pix2
= (pix2
* d
) >> 23;
4293 *destPtr
++ = (Guchar
)pix0
;
4294 *destPtr
++ = (Guchar
)pix1
;
4295 *destPtr
++ = (Guchar
)pix2
;
4298 case splashModeXBGR8
:
4300 // compute the final pixel
4301 pix0
= pix1
= pix2
= 0;
4302 for (i
= 0; i
< xStep
; ++i
) {
4304 pix1
+= pixBuf
[xx
+1];
4305 pix2
+= pixBuf
[xx
+2];
4308 // pix / xStep * yStep
4309 pix0
= (pix0
* d
) >> 23;
4310 pix1
= (pix1
* d
) >> 23;
4311 pix2
= (pix2
* d
) >> 23;
4314 *destPtr
++ = (Guchar
)pix2
;
4315 *destPtr
++ = (Guchar
)pix1
;
4316 *destPtr
++ = (Guchar
)pix0
;
4317 *destPtr
++ = (Guchar
)255;
4320 case splashModeBGR8
:
4322 // compute the final pixel
4323 pix0
= pix1
= pix2
= 0;
4324 for (i
= 0; i
< xStep
; ++i
) {
4326 pix1
+= pixBuf
[xx
+1];
4327 pix2
+= pixBuf
[xx
+2];
4330 // pix / xStep * yStep
4331 pix0
= (pix0
* d
) >> 23;
4332 pix1
= (pix1
* d
) >> 23;
4333 pix2
= (pix2
* d
) >> 23;
4336 *destPtr
++ = (Guchar
)pix2
;
4337 *destPtr
++ = (Guchar
)pix1
;
4338 *destPtr
++ = (Guchar
)pix0
;
4342 case splashModeCMYK8
:
4344 // compute the final pixel
4345 pix0
= pix1
= pix2
= pix3
= 0;
4346 for (i
= 0; i
< xStep
; ++i
) {
4348 pix1
+= pixBuf
[xx
+1];
4349 pix2
+= pixBuf
[xx
+2];
4350 pix3
+= pixBuf
[xx
+3];
4353 // pix / xStep * yStep
4354 pix0
= (pix0
* d
) >> 23;
4355 pix1
= (pix1
* d
) >> 23;
4356 pix2
= (pix2
* d
) >> 23;
4357 pix3
= (pix3
* d
) >> 23;
4360 *destPtr
++ = (Guchar
)pix0
;
4361 *destPtr
++ = (Guchar
)pix1
;
4362 *destPtr
++ = (Guchar
)pix2
;
4363 *destPtr
++ = (Guchar
)pix3
;
4365 case splashModeDeviceN8
:
4367 // compute the final pixel
4368 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4370 for (i
= 0; i
< xStep
; ++i
) {
4371 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++) {
4372 pix
[cp
] += pixBuf
[xx
+ cp
];
4374 xx
+= (SPOT_NCOMPS
+4);
4376 // pix / xStep * yStep
4377 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4378 pix
[cp
] = (pix
[cp
] * d
) >> 23;
4381 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4382 *destPtr
++ = (Guchar
)pix
[cp
];
4387 case splashModeMono1
: // mono1 is not allowed
4395 for (i
= 0; i
< xStep
; ++i
, ++xxa
) {
4396 alpha
+= alphaPixBuf
[xxa
];
4398 // alpha / xStep * yStep
4399 alpha
= (alpha
* d
) >> 23;
4400 *destAlphaPtr
++ = (Guchar
)alpha
;
4406 gfree(alphaLineBuf
);
4411 void Splash::scaleImageYdXu(SplashImageSource src
, void *srcData
,
4412 SplashColorMode srcMode
, int nComps
,
4413 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4414 int scaledWidth
, int scaledHeight
,
4415 SplashBitmap
*dest
) {
4416 Guchar
*lineBuf
, *alphaLineBuf
;
4417 Guint
*pixBuf
, *alphaPixBuf
;
4418 Guint pix
[splashMaxColorComps
];
4420 Guchar
*destPtr
, *destAlphaPtr
;
4421 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, d
;
4424 // Bresenham parameters for y scale
4425 yp
= srcHeight
/ scaledHeight
;
4426 yq
= srcHeight
% scaledHeight
;
4428 // Bresenham parameters for x scale
4429 xp
= scaledWidth
/ srcWidth
;
4430 xq
= scaledWidth
% srcWidth
;
4433 lineBuf
= (Guchar
*)gmallocn(srcWidth
, nComps
);
4434 pixBuf
= (Guint
*)gmallocn(srcWidth
, nComps
* sizeof(int));
4436 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4437 alphaPixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
4439 alphaLineBuf
= NULL
;
4443 // init y scale Bresenham
4446 destPtr
= dest
->data
;
4447 destAlphaPtr
= dest
->alpha
;
4448 for (y
= 0; y
< scaledHeight
; ++y
) {
4450 // y scale Bresenham
4451 if ((yt
+= yq
) >= scaledHeight
) {
4458 // read rows from image
4459 memset(pixBuf
, 0, srcWidth
* nComps
* sizeof(int));
4461 memset(alphaPixBuf
, 0, srcWidth
* sizeof(int));
4463 for (i
= 0; i
< yStep
; ++i
) {
4464 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4465 for (j
= 0; j
< srcWidth
* nComps
; ++j
) {
4466 pixBuf
[j
] += lineBuf
[j
];
4469 for (j
= 0; j
< srcWidth
; ++j
) {
4470 alphaPixBuf
[j
] += alphaLineBuf
[j
];
4475 // init x scale Bresenham
4477 d
= (1 << 23) / yStep
;
4479 for (x
= 0; x
< srcWidth
; ++x
) {
4481 // x scale Bresenham
4482 if ((xt
+= xq
) >= srcWidth
) {
4489 // compute the final pixel
4490 for (i
= 0; i
< nComps
; ++i
) {
4492 pix
[i
] = (pixBuf
[x
* nComps
+ i
] * d
) >> 23;
4497 case splashModeMono1
: // mono1 is not allowed
4499 case splashModeMono8
:
4500 for (i
= 0; i
< xStep
; ++i
) {
4501 *destPtr
++ = (Guchar
)pix
[0];
4504 case splashModeRGB8
:
4505 for (i
= 0; i
< xStep
; ++i
) {
4506 *destPtr
++ = (Guchar
)pix
[0];
4507 *destPtr
++ = (Guchar
)pix
[1];
4508 *destPtr
++ = (Guchar
)pix
[2];
4511 case splashModeXBGR8
:
4512 for (i
= 0; i
< xStep
; ++i
) {
4513 *destPtr
++ = (Guchar
)pix
[2];
4514 *destPtr
++ = (Guchar
)pix
[1];
4515 *destPtr
++ = (Guchar
)pix
[0];
4516 *destPtr
++ = (Guchar
)255;
4519 case splashModeBGR8
:
4520 for (i
= 0; i
< xStep
; ++i
) {
4521 *destPtr
++ = (Guchar
)pix
[2];
4522 *destPtr
++ = (Guchar
)pix
[1];
4523 *destPtr
++ = (Guchar
)pix
[0];
4527 case splashModeCMYK8
:
4528 for (i
= 0; i
< xStep
; ++i
) {
4529 *destPtr
++ = (Guchar
)pix
[0];
4530 *destPtr
++ = (Guchar
)pix
[1];
4531 *destPtr
++ = (Guchar
)pix
[2];
4532 *destPtr
++ = (Guchar
)pix
[3];
4535 case splashModeDeviceN8
:
4536 for (i
= 0; i
< xStep
; ++i
) {
4537 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4538 *destPtr
++ = (Guchar
)pix
[cp
];
4546 // alphaPixBuf[] / yStep
4547 alpha
= (alphaPixBuf
[x
] * d
) >> 23;
4548 for (i
= 0; i
< xStep
; ++i
) {
4549 *destAlphaPtr
++ = (Guchar
)alpha
;
4556 gfree(alphaLineBuf
);
4561 void Splash::scaleImageYuXd(SplashImageSource src
, void *srcData
,
4562 SplashColorMode srcMode
, int nComps
,
4563 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4564 int scaledWidth
, int scaledHeight
,
4565 SplashBitmap
*dest
) {
4566 Guchar
*lineBuf
, *alphaLineBuf
;
4567 Guint pix
[splashMaxColorComps
];
4569 Guchar
*destPtr0
, *destPtr
, *destAlphaPtr0
, *destAlphaPtr
;
4570 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, xxa
, d
, d0
, d1
;
4573 // Bresenham parameters for y scale
4574 yp
= scaledHeight
/ srcHeight
;
4575 yq
= scaledHeight
% srcHeight
;
4577 // Bresenham parameters for x scale
4578 xp
= srcWidth
/ scaledWidth
;
4579 xq
= srcWidth
% scaledWidth
;
4582 lineBuf
= (Guchar
*)gmallocn_checkoverflow(srcWidth
, nComps
);
4583 if (unlikely(!lineBuf
))
4586 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4588 alphaLineBuf
= NULL
;
4591 // init y scale Bresenham
4594 destPtr0
= dest
->data
;
4595 destAlphaPtr0
= dest
->alpha
;
4596 for (y
= 0; y
< srcHeight
; ++y
) {
4598 // y scale Bresenham
4599 if ((yt
+= yq
) >= srcHeight
) {
4606 // read row from image
4607 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4609 // init x scale Bresenham
4611 d0
= (1 << 23) / xp
;
4612 d1
= (1 << 23) / (xp
+ 1);
4615 for (x
= 0; x
< scaledWidth
; ++x
) {
4617 // x scale Bresenham
4618 if ((xt
+= xq
) >= scaledWidth
) {
4627 // compute the final pixel
4628 for (i
= 0; i
< nComps
; ++i
) {
4631 for (i
= 0; i
< xStep
; ++i
) {
4632 for (j
= 0; j
< nComps
; ++j
, ++xx
) {
4633 pix
[j
] += lineBuf
[xx
];
4636 for (i
= 0; i
< nComps
; ++i
) {
4638 pix
[i
] = (pix
[i
] * d
) >> 23;
4643 case splashModeMono1
: // mono1 is not allowed
4645 case splashModeMono8
:
4646 for (i
= 0; i
< yStep
; ++i
) {
4647 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4648 *destPtr
++ = (Guchar
)pix
[0];
4651 case splashModeRGB8
:
4652 for (i
= 0; i
< yStep
; ++i
) {
4653 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4654 *destPtr
++ = (Guchar
)pix
[0];
4655 *destPtr
++ = (Guchar
)pix
[1];
4656 *destPtr
++ = (Guchar
)pix
[2];
4659 case splashModeXBGR8
:
4660 for (i
= 0; i
< yStep
; ++i
) {
4661 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4662 *destPtr
++ = (Guchar
)pix
[2];
4663 *destPtr
++ = (Guchar
)pix
[1];
4664 *destPtr
++ = (Guchar
)pix
[0];
4665 *destPtr
++ = (Guchar
)255;
4668 case splashModeBGR8
:
4669 for (i
= 0; i
< yStep
; ++i
) {
4670 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4671 *destPtr
++ = (Guchar
)pix
[2];
4672 *destPtr
++ = (Guchar
)pix
[1];
4673 *destPtr
++ = (Guchar
)pix
[0];
4677 case splashModeCMYK8
:
4678 for (i
= 0; i
< yStep
; ++i
) {
4679 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4680 *destPtr
++ = (Guchar
)pix
[0];
4681 *destPtr
++ = (Guchar
)pix
[1];
4682 *destPtr
++ = (Guchar
)pix
[2];
4683 *destPtr
++ = (Guchar
)pix
[3];
4686 case splashModeDeviceN8
:
4687 for (i
= 0; i
< yStep
; ++i
) {
4688 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4689 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4690 *destPtr
++ = (Guchar
)pix
[cp
];
4699 for (i
= 0; i
< xStep
; ++i
, ++xxa
) {
4700 alpha
+= alphaLineBuf
[xxa
];
4703 alpha
= (alpha
* d
) >> 23;
4704 for (i
= 0; i
< yStep
; ++i
) {
4705 destAlphaPtr
= destAlphaPtr0
+ i
* scaledWidth
+ x
;
4706 *destAlphaPtr
= (Guchar
)alpha
;
4711 destPtr0
+= yStep
* scaledWidth
* nComps
;
4713 destAlphaPtr0
+= yStep
* scaledWidth
;
4717 gfree(alphaLineBuf
);
4721 void Splash::scaleImageYuXu(SplashImageSource src
, void *srcData
,
4722 SplashColorMode srcMode
, int nComps
,
4723 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4724 int scaledWidth
, int scaledHeight
,
4725 SplashBitmap
*dest
) {
4726 Guchar
*lineBuf
, *alphaLineBuf
;
4727 Guint pix
[splashMaxColorComps
];
4729 Guchar
*destPtr0
, *destPtr
, *destAlphaPtr0
, *destAlphaPtr
;
4730 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
;
4733 // Bresenham parameters for y scale
4734 yp
= scaledHeight
/ srcHeight
;
4735 yq
= scaledHeight
% srcHeight
;
4737 // Bresenham parameters for x scale
4738 xp
= scaledWidth
/ srcWidth
;
4739 xq
= scaledWidth
% srcWidth
;
4742 lineBuf
= (Guchar
*)gmallocn(srcWidth
, nComps
);
4744 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4746 alphaLineBuf
= NULL
;
4749 // init y scale Bresenham
4752 destPtr0
= dest
->data
;
4753 destAlphaPtr0
= dest
->alpha
;
4754 for (y
= 0; y
< srcHeight
; ++y
) {
4756 // y scale Bresenham
4757 if ((yt
+= yq
) >= srcHeight
) {
4764 // read row from image
4765 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4767 // init x scale Bresenham
4771 for (x
= 0; x
< srcWidth
; ++x
) {
4773 // x scale Bresenham
4774 if ((xt
+= xq
) >= srcWidth
) {
4781 // compute the final pixel
4782 for (i
= 0; i
< nComps
; ++i
) {
4783 pix
[i
] = lineBuf
[x
* nComps
+ i
];
4788 case splashModeMono1
: // mono1 is not allowed
4790 case splashModeMono8
:
4791 for (i
= 0; i
< yStep
; ++i
) {
4792 for (j
= 0; j
< xStep
; ++j
) {
4793 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4794 *destPtr
++ = (Guchar
)pix
[0];
4798 case splashModeRGB8
:
4799 for (i
= 0; i
< yStep
; ++i
) {
4800 for (j
= 0; j
< xStep
; ++j
) {
4801 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4802 *destPtr
++ = (Guchar
)pix
[0];
4803 *destPtr
++ = (Guchar
)pix
[1];
4804 *destPtr
++ = (Guchar
)pix
[2];
4808 case splashModeXBGR8
:
4809 for (i
= 0; i
< yStep
; ++i
) {
4810 for (j
= 0; j
< xStep
; ++j
) {
4811 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4812 *destPtr
++ = (Guchar
)pix
[2];
4813 *destPtr
++ = (Guchar
)pix
[1];
4814 *destPtr
++ = (Guchar
)pix
[0];
4815 *destPtr
++ = (Guchar
)255;
4819 case splashModeBGR8
:
4820 for (i
= 0; i
< yStep
; ++i
) {
4821 for (j
= 0; j
< xStep
; ++j
) {
4822 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4823 *destPtr
++ = (Guchar
)pix
[2];
4824 *destPtr
++ = (Guchar
)pix
[1];
4825 *destPtr
++ = (Guchar
)pix
[0];
4830 case splashModeCMYK8
:
4831 for (i
= 0; i
< yStep
; ++i
) {
4832 for (j
= 0; j
< xStep
; ++j
) {
4833 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4834 *destPtr
++ = (Guchar
)pix
[0];
4835 *destPtr
++ = (Guchar
)pix
[1];
4836 *destPtr
++ = (Guchar
)pix
[2];
4837 *destPtr
++ = (Guchar
)pix
[3];
4841 case splashModeDeviceN8
:
4842 for (i
= 0; i
< yStep
; ++i
) {
4843 for (j
= 0; j
< xStep
; ++j
) {
4844 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4845 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4846 *destPtr
++ = (Guchar
)pix
[cp
];
4855 alpha
= alphaLineBuf
[x
];
4856 for (i
= 0; i
< yStep
; ++i
) {
4857 for (j
= 0; j
< xStep
; ++j
) {
4858 destAlphaPtr
= destAlphaPtr0
+ i
* scaledWidth
+ xx
+ j
;
4859 *destAlphaPtr
= (Guchar
)alpha
;
4867 destPtr0
+= yStep
* scaledWidth
* nComps
;
4869 destAlphaPtr0
+= yStep
* scaledWidth
;
4873 gfree(alphaLineBuf
);
4877 // expand source row to scaledWidth using linear interpolation
4878 static void expandRow(Guchar
*srcBuf
, Guchar
*dstBuf
, int srcWidth
, int scaledWidth
, int nComps
)
4880 double xStep
= (double)srcWidth
/scaledWidth
;
4885 // pad the source with an extra pixel equal to the last pixel
4886 // so that when xStep is inside the last pixel we still have two
4887 // pixels to interpolate between.
4888 for (int i
= 0; i
< nComps
; i
++)
4889 srcBuf
[srcWidth
*nComps
+ i
] = srcBuf
[(srcWidth
-1)*nComps
+ i
];
4891 for (int x
= 0; x
< scaledWidth
; x
++) {
4892 xFrac
= modf(xSrc
, &xInt
);
4894 for (int c
= 0; c
< nComps
; c
++) {
4895 dstBuf
[nComps
*x
+ c
] = srcBuf
[nComps
*p
+ c
]*(1.0 - xFrac
) + srcBuf
[nComps
*(p
+1) + c
]*xFrac
;
4901 // Scale up image using bilinear interpolation
4902 void Splash::scaleImageYuXuBilinear(SplashImageSource src
, void *srcData
,
4903 SplashColorMode srcMode
, int nComps
,
4904 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4905 int scaledWidth
, int scaledHeight
,
4906 SplashBitmap
*dest
) {
4907 Guchar
*srcBuf
, *lineBuf1
, *lineBuf2
, *alphaSrcBuf
, *alphaLineBuf1
, *alphaLineBuf2
;
4908 Guint pix
[splashMaxColorComps
];
4909 Guchar
*destPtr0
, *destPtr
, *destAlphaPtr0
, *destAlphaPtr
;
4912 if (srcWidth
< 1 || srcHeight
< 1)
4916 srcBuf
= (Guchar
*)gmallocn(srcWidth
+1, nComps
); // + 1 pixel of padding
4917 lineBuf1
= (Guchar
*)gmallocn(scaledWidth
, nComps
);
4918 lineBuf2
= (Guchar
*)gmallocn(scaledWidth
, nComps
);
4920 alphaSrcBuf
= (Guchar
*)gmalloc(srcWidth
+1); // + 1 pixel of padding
4921 alphaLineBuf1
= (Guchar
*)gmalloc(scaledWidth
);
4922 alphaLineBuf2
= (Guchar
*)gmalloc(scaledWidth
);
4925 alphaLineBuf1
= NULL
;
4926 alphaLineBuf2
= NULL
;
4930 double yStep
= (double)srcHeight
/scaledHeight
;
4932 int currentSrcRow
= -1;
4933 (*src
)(srcData
, srcBuf
, alphaSrcBuf
);
4934 expandRow(srcBuf
, lineBuf2
, srcWidth
, scaledWidth
, nComps
);
4936 expandRow(alphaSrcBuf
, alphaLineBuf2
, srcWidth
, scaledWidth
, 1);
4938 destPtr0
= dest
->data
;
4939 destAlphaPtr0
= dest
->alpha
;
4940 for (int y
= 0; y
< scaledHeight
; y
++) {
4941 yFrac
= modf(ySrc
, &yInt
);
4942 if ((int)yInt
> currentSrcRow
) {
4944 // Copy line2 data to line1 and get next line2 data.
4945 // If line2 already contains the last source row we don't touch it.
4946 // This effectively adds an extra row of padding for interpolating the
4947 // last source row with.
4948 memcpy(lineBuf1
, lineBuf2
, scaledWidth
* nComps
);
4950 memcpy(alphaLineBuf1
, alphaLineBuf2
, scaledWidth
);
4951 if (currentSrcRow
< srcHeight
) {
4952 (*src
)(srcData
, srcBuf
, alphaSrcBuf
);
4953 expandRow(srcBuf
, lineBuf2
, srcWidth
, scaledWidth
, nComps
);
4955 expandRow(alphaSrcBuf
, alphaLineBuf2
, srcWidth
, scaledWidth
, 1);
4959 // write row y using linear interpolation on lineBuf1 and lineBuf2
4960 for (int x
= 0; x
< scaledWidth
; ++x
) {
4961 // compute the final pixel
4962 for (i
= 0; i
< nComps
; ++i
) {
4963 pix
[i
] = lineBuf1
[x
*nComps
+ i
]*(1.0 - yFrac
) + lineBuf2
[x
*nComps
+ i
]*yFrac
;
4967 destPtr
= destPtr0
+ (y
* scaledWidth
+ x
) * nComps
;
4969 case splashModeMono1
: // mono1 is not allowed
4971 case splashModeMono8
:
4972 *destPtr
++ = (Guchar
)pix
[0];
4974 case splashModeRGB8
:
4975 *destPtr
++ = (Guchar
)pix
[0];
4976 *destPtr
++ = (Guchar
)pix
[1];
4977 *destPtr
++ = (Guchar
)pix
[2];
4979 case splashModeXBGR8
:
4980 *destPtr
++ = (Guchar
)pix
[2];
4981 *destPtr
++ = (Guchar
)pix
[1];
4982 *destPtr
++ = (Guchar
)pix
[0];
4983 *destPtr
++ = (Guchar
)255;
4985 case splashModeBGR8
:
4986 *destPtr
++ = (Guchar
)pix
[2];
4987 *destPtr
++ = (Guchar
)pix
[1];
4988 *destPtr
++ = (Guchar
)pix
[0];
4991 case splashModeCMYK8
:
4992 *destPtr
++ = (Guchar
)pix
[0];
4993 *destPtr
++ = (Guchar
)pix
[1];
4994 *destPtr
++ = (Guchar
)pix
[2];
4995 *destPtr
++ = (Guchar
)pix
[3];
4997 case splashModeDeviceN8
:
4998 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4999 *destPtr
++ = (Guchar
)pix
[cp
];
5006 destAlphaPtr
= destAlphaPtr0
+ y
*scaledWidth
+ x
;
5007 *destAlphaPtr
= alphaLineBuf1
[x
]*(1.0 - yFrac
) + alphaLineBuf2
[x
]*yFrac
;
5015 gfree(alphaLineBuf1
);
5016 gfree(alphaLineBuf2
);
5022 void Splash::vertFlipImage(SplashBitmap
*img
, int width
, int height
,
5028 if (unlikely(img
->data
== NULL
)) {
5029 error(errInternal
, -1, "img->data is NULL in Splash::vertFlipImage");
5034 lineBuf
= (Guchar
*)gmalloc(w
);
5035 for (p0
= img
->data
, p1
= img
->data
+ (height
- 1) * w
;
5038 memcpy(lineBuf
, p0
, w
);
5040 memcpy(p1
, lineBuf
, w
);
5043 for (p0
= img
->alpha
, p1
= img
->alpha
+ (height
- 1) * width
;
5045 p0
+= width
, p1
-= width
) {
5046 memcpy(lineBuf
, p0
, width
);
5047 memcpy(p0
, p1
, width
);
5048 memcpy(p1
, lineBuf
, width
);
5054 void Splash::blitImage(SplashBitmap
*src
, GBool srcAlpha
, int xDest
, int yDest
) {
5055 SplashClipResult clipRes
= state
->clip
->testRect(xDest
, yDest
, xDest
+ src
->getWidth() - 1, yDest
+ src
->getHeight() - 1);
5056 if (clipRes
!= splashClipAllOutside
) {
5057 blitImage(src
, srcAlpha
, xDest
, yDest
, clipRes
);
5061 void Splash::blitImage(SplashBitmap
*src
, GBool srcAlpha
, int xDest
, int yDest
,
5062 SplashClipResult clipRes
) {
5066 int w
, h
, x0
, y0
, x1
, y1
, x
, y
;
5068 // split the image into clipped and unclipped regions
5069 w
= src
->getWidth();
5070 h
= src
->getHeight();
5071 if (clipRes
== splashClipAllInside
) {
5077 if (state
->clip
->getNumPaths()) {
5081 if ((x0
= splashCeil(state
->clip
->getXMin()) - xDest
) < 0) {
5084 if ((y0
= splashCeil(state
->clip
->getYMin()) - yDest
) < 0) {
5087 if ((x1
= splashFloor(state
->clip
->getXMax()) - xDest
) > w
) {
5093 if ((y1
= splashFloor(state
->clip
->getYMax()) - yDest
) > h
) {
5102 // draw the unclipped region
5103 if (x0
< w
&& y0
< h
&& x0
< x1
&& y0
< y1
) {
5104 pipeInit(&pipe
, xDest
+ x0
, yDest
+ y0
, NULL
, pixel
,
5105 (Guchar
)splashRound(state
->fillAlpha
* 255), srcAlpha
, gFalse
);
5107 for (y
= y0
; y
< y1
; ++y
) {
5108 pipeSetXY(&pipe
, xDest
+ x0
, yDest
+ y
);
5109 ap
= src
->getAlphaPtr() + y
* w
+ x0
;
5110 for (x
= x0
; x
< x1
; ++x
) {
5111 src
->getPixel(x
, y
, pixel
);
5113 (this->*pipe
.run
)(&pipe
);
5117 for (y
= y0
; y
< y1
; ++y
) {
5118 pipeSetXY(&pipe
, xDest
+ x0
, yDest
+ y
);
5119 for (x
= x0
; x
< x1
; ++x
) {
5120 src
->getPixel(x
, y
, pixel
);
5121 (this->*pipe
.run
)(&pipe
);
5125 updateModX(xDest
+ x0
);
5126 updateModX(xDest
+ x1
- 1);
5127 updateModY(yDest
+ y0
);
5128 updateModY(yDest
+ y1
- 1);
5131 // draw the clipped regions
5133 blitImageClipped(src
, srcAlpha
, 0, 0, xDest
, yDest
, w
, y0
);
5136 blitImageClipped(src
, srcAlpha
, 0, y1
, xDest
, yDest
+ y1
, w
, h
- y1
);
5138 if (x0
> 0 && y0
< y1
) {
5139 blitImageClipped(src
, srcAlpha
, 0, y0
, xDest
, yDest
+ y0
, x0
, y1
- y0
);
5141 if (x1
< w
&& y0
< y1
) {
5142 blitImageClipped(src
, srcAlpha
, x1
, y0
, xDest
+ x1
, yDest
+ y0
,
5147 void Splash::blitImageClipped(SplashBitmap
*src
, GBool srcAlpha
,
5148 int xSrc
, int ySrc
, int xDest
, int yDest
,
5155 if (vectorAntialias
) {
5156 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5157 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
5160 for (y
= 0; y
< h
; ++y
) {
5161 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5162 for (x
= 0; x
< w
; ++x
) {
5163 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5165 drawAAPixel(&pipe
, xDest
+ x
, yDest
+ y
);
5169 for (y
= 0; y
< h
; ++y
) {
5170 for (x
= 0; x
< w
; ++x
) {
5171 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5173 drawAAPixel(&pipe
, xDest
+ x
, yDest
+ y
);
5178 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5179 (Guchar
)splashRound(state
->fillAlpha
* 255), srcAlpha
, gFalse
);
5181 for (y
= 0; y
< h
; ++y
) {
5182 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5183 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5184 for (x
= 0; x
< w
; ++x
) {
5185 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5186 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5188 (this->*pipe
.run
)(&pipe
);
5189 updateModX(xDest
+ x
);
5190 updateModY(yDest
+ y
);
5198 for (y
= 0; y
< h
; ++y
) {
5199 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5200 for (x
= 0; x
< w
; ++x
) {
5201 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5202 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5203 (this->*pipe
.run
)(&pipe
);
5204 updateModX(xDest
+ x
);
5205 updateModY(yDest
+ y
);
5215 SplashError
Splash::composite(SplashBitmap
*src
, int xSrc
, int ySrc
,
5216 int xDest
, int yDest
, int w
, int h
,
5217 GBool noClip
, GBool nonIsolated
,
5218 GBool knockout
, SplashCoord knockoutOpacity
) {
5225 if (src
->mode
!= bitmap
->mode
) {
5226 return splashErrModeMismatch
;
5229 if (unlikely(!bitmap
->data
)) {
5230 return splashErrZeroImage
;
5233 if(src
->getSeparationList()->getLength() > bitmap
->getSeparationList()->getLength()) {
5234 for (x
= bitmap
->getSeparationList()->getLength(); x
< src
->getSeparationList()->getLength(); x
++)
5235 bitmap
->getSeparationList()->append(((GfxSeparationColorSpace
*)src
->getSeparationList()->get(x
))->copy());
5238 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5239 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, nonIsolated
,
5240 knockout
, (Guchar
)splashRound(knockoutOpacity
* 255));
5242 for (y
= 0; y
< h
; ++y
) {
5243 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5244 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5245 for (x
= 0; x
< w
; ++x
) {
5246 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5248 // this uses shape instead of alpha, which isn't technically
5249 // correct, but works out the same
5251 (this->*pipe
.run
)(&pipe
);
5255 updateModX(xDest
+ w
- 1);
5257 updateModY(yDest
+ h
- 1);
5259 for (y
= 0; y
< h
; ++y
) {
5260 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5261 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5262 for (x
= 0; x
< w
; ++x
) {
5263 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5265 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5266 // this uses shape instead of alpha, which isn't technically
5267 // correct, but works out the same
5269 (this->*pipe
.run
)(&pipe
);
5270 updateModX(xDest
+ x
);
5271 updateModY(yDest
+ y
);
5279 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5280 (Guchar
)splashRound(state
->fillAlpha
* 255), gFalse
, nonIsolated
);
5282 for (y
= 0; y
< h
; ++y
) {
5283 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5284 for (x
= 0; x
< w
; ++x
) {
5285 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5286 (this->*pipe
.run
)(&pipe
);
5290 updateModX(xDest
+ w
- 1);
5292 updateModY(yDest
+ h
- 1);
5294 for (y
= 0; y
< h
; ++y
) {
5295 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5296 for (x
= 0; x
< w
; ++x
) {
5297 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5298 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5299 (this->*pipe
.run
)(&pipe
);
5300 updateModX(xDest
+ x
);
5301 updateModY(yDest
+ y
);
5313 void Splash::compositeBackground(SplashColorPtr color
) {
5316 Guchar alpha
, alpha1
, c
, color0
, color1
, color2
;
5319 Guchar colorsp
[SPOT_NCOMPS
+4], cp
;
5323 if (unlikely(bitmap
->alpha
== NULL
)) {
5324 error(errInternal
, -1, "bitmap->alpha is NULL in Splash::compositeBackground");
5328 switch (bitmap
->mode
) {
5329 case splashModeMono1
:
5331 for (y
= 0; y
< bitmap
->height
; ++y
) {
5332 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5333 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5335 for (x
= 0; x
< bitmap
->width
; ++x
) {
5337 alpha1
= 255 - alpha
;
5338 c
= (*p
& mask
) ? 0xff : 0x00;
5339 c
= div255(alpha1
* color0
+ alpha
* c
);
5345 if (!(mask
>>= 1)) {
5352 case splashModeMono8
:
5354 for (y
= 0; y
< bitmap
->height
; ++y
) {
5355 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5356 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5357 for (x
= 0; x
< bitmap
->width
; ++x
) {
5359 alpha1
= 255 - alpha
;
5360 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5365 case splashModeRGB8
:
5366 case splashModeBGR8
:
5370 for (y
= 0; y
< bitmap
->height
; ++y
) {
5371 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5372 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5373 for (x
= 0; x
< bitmap
->width
; ++x
) {
5381 else if (alpha
!= 255)
5383 alpha1
= 255 - alpha
;
5384 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5385 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
5386 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
5392 case splashModeXBGR8
:
5396 for (y
= 0; y
< bitmap
->height
; ++y
) {
5397 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5398 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5399 for (x
= 0; x
< bitmap
->width
; ++x
) {
5407 else if (alpha
!= 255)
5409 alpha1
= 255 - alpha
;
5410 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5411 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
5412 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
5420 case splashModeCMYK8
:
5425 for (y
= 0; y
< bitmap
->height
; ++y
) {
5426 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5427 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5428 for (x
= 0; x
< bitmap
->width
; ++x
) {
5437 else if (alpha
!= 255)
5439 alpha1
= 255 - alpha
;
5440 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5441 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
5442 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
5443 p
[3] = div255(alpha1
* color3
+ alpha
* p
[3]);
5449 case splashModeDeviceN8
:
5450 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5451 colorsp
[cp
] = color
[cp
];
5452 for (y
= 0; y
< bitmap
->height
; ++y
) {
5453 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5454 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5455 for (x
= 0; x
< bitmap
->width
; ++x
) {
5459 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5460 p
[cp
] = colorsp
[cp
];
5462 else if (alpha
!= 255)
5464 alpha1
= 255 - alpha
;
5465 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5466 p
[cp
] = div255(alpha1
* colorsp
[cp
] + alpha
* p
[cp
]);
5468 p
+= (SPOT_NCOMPS
+4);
5474 memset(bitmap
->alpha
, 255, bitmap
->width
* bitmap
->height
);
5477 GBool
Splash::gouraudTriangleShadedFill(SplashGouraudColor
*shading
)
5479 double xdbl
[3] = {0., 0., 0.};
5480 double ydbl
[3] = {0., 0., 0.};
5481 int x
[3] = {0, 0, 0};
5482 int y
[3] = {0, 0, 0};
5483 double xt
=0., xa
=0., yt
=0.;
5484 double ca
=0., ct
=0.;
5486 // triangle interpolation:
5488 double scanLimitMapL
[2] = {0., 0.};
5489 double scanLimitMapR
[2] = {0., 0.};
5490 double scanColorMapL
[2] = {0., 0.};
5491 double scanColorMapR
[2] = {0., 0.};
5492 double scanColorMap
[2] = {0., 0.};
5493 int scanEdgeL
[2] = { 0, 0 };
5494 int scanEdgeR
[2] = { 0, 0 };
5495 GBool hasFurtherSegment
= gFalse
;
5497 int scanLineOff
= 0;
5499 int scanLimitR
= 0, scanLimitL
= 0;
5501 int bitmapWidth
= bitmap
->getWidth();
5502 SplashClip
* clip
= getClip();
5503 SplashBitmap
*blitTarget
= bitmap
;
5504 SplashColorPtr bitmapData
= bitmap
->getDataPtr();
5505 int bitmapOffLimit
= bitmap
->getHeight() * bitmap
->getRowSize();
5506 SplashColorPtr bitmapAlpha
= bitmap
->getAlphaPtr();
5507 SplashColorPtr cur
= NULL
;
5508 SplashCoord
* userToCanvasMatrix
= getMatrix();
5509 SplashColorMode bitmapMode
= bitmap
->getMode();
5510 GBool hasAlpha
= (bitmapAlpha
!= NULL
);
5511 int rowSize
= bitmap
->getRowSize();
5513 switch (bitmapMode
) {
5514 case splashModeMono1
:
5516 case splashModeMono8
:
5519 case splashModeRGB8
:
5522 case splashModeBGR8
:
5525 case splashModeXBGR8
:
5529 case splashModeCMYK8
:
5532 case splashModeDeviceN8
:
5533 colorComps
=SPOT_NCOMPS
+4;
5539 SplashColor cSrcVal
;
5541 pipeInit(&pipe
, 0, 0, NULL
, cSrcVal
, (Guchar
)splashRound(state
->strokeAlpha
* 255), gFalse
, gFalse
);
5543 if (vectorAntialias
) {
5545 return gFalse
; // fall back to old behaviour
5550 // 1. If pipe->noTransparency && !state->blendFunc
5551 // -> blit directly into the drawing surface!
5552 // -> disable alpha manually.
5554 // - blit also directly, but into an intermediate surface.
5555 // Afterwards, blit the intermediate surface using the drawing pipeline.
5556 // This is necessary because triangle elements can be on top of each
5557 // other, so the complete shading needs to be drawn before opacity is
5559 // - the final step, is performed using a SplashPipe:
5560 // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
5561 // - invoke drawPixel(&pipe,X,Y,bNoClip);
5562 GBool bDirectBlit
= vectorAntialias
? gFalse
: pipe
.noTransparency
&& !state
->blendFunc
;
5564 blitTarget
= new SplashBitmap(bitmap
->getWidth(),
5565 bitmap
->getHeight(),
5566 bitmap
->getRowPad(),
5569 bitmap
->getRowSize() >= 0);
5570 bitmapData
= blitTarget
->getDataPtr();
5571 bitmapAlpha
= blitTarget
->getAlphaPtr();
5573 // initialisation seems to be necessary:
5574 int S
= bitmap
->getWidth() * bitmap
->getHeight();
5575 for (int i
= 0; i
< S
; ++i
)
5580 if (shading
->isParameterized()) {
5584 for (int i
= 0; i
< shading
->getNTriangles(); ++i
) {
5585 shading
->getTriangle(i
,
5586 xdbl
+ 0, ydbl
+ 0, color
+ 0,
5587 xdbl
+ 1, ydbl
+ 1, color
+ 1,
5588 xdbl
+ 2, ydbl
+ 2, color
+ 2);
5589 for (int m
= 0; m
< 3; ++m
) {
5590 xt
= xdbl
[m
] * (double)userToCanvasMatrix
[0] + ydbl
[m
] * (double)userToCanvasMatrix
[2] + (double)userToCanvasMatrix
[4];
5591 yt
= xdbl
[m
] * (double)userToCanvasMatrix
[1] + ydbl
[m
] * (double)userToCanvasMatrix
[3] + (double)userToCanvasMatrix
[5];
5594 // we operate on scanlines which are integer offsets into the
5595 // raster image. The double offsets are of no use here.
5596 x
[m
] = splashRound(xt
);
5597 y
[m
] = splashRound(yt
);
5599 // sort according to y coordinate to simplify sweep through scanlines:
5604 Guswap(color
[0], color
[1]);
5606 // first two are sorted.
5607 assert(y
[0] <= y
[1]);
5611 double tmpC
= color
[2];
5612 x
[2] = x
[1]; y
[2] = y
[1]; color
[2] = color
[1];
5615 x
[1] = x
[0]; y
[1] = y
[0]; color
[1] = color
[0];
5616 x
[0] = tmpX
; y
[0] = tmpY
; color
[0] = tmpC
;
5618 x
[1] = tmpX
; y
[1] = tmpY
; color
[1] = tmpC
;
5621 // first three are sorted
5622 assert(y
[0] <= y
[1]);
5623 assert(y
[1] <= y
[2]);
5626 // this here is det( T ) == 0
5627 // where T is the matrix to map to barycentric coordinates.
5628 if ((x
[0] - x
[2]) * (y
[1] - y
[2]) - (x
[1] - x
[2]) * (y
[0] - y
[2]) == 0)
5629 continue; // degenerate triangle.
5631 // this here initialises the scanline generation.
5632 // We start with low Y coordinates and sweep up to the large Y
5635 // scanEdgeL[m] in {0,1,2} m=0,1
5636 // scanEdgeR[m] in {0,1,2} m=0,1
5638 // are the two edges between which scanlines are (currently)
5639 // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
5640 // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
5646 scanEdgeL
[1] = scanEdgeR
[1] = 2;
5649 scanEdgeL
[1] = 1; scanEdgeR
[1] = 2;
5651 assert(y
[scanEdgeL
[0]] < y
[scanEdgeL
[1]]);
5652 assert(y
[scanEdgeR
[0]] < y
[scanEdgeR
[1]]);
5654 // Ok. Now prepare the linear maps which map the y coordinate of
5655 // the current scanline to the corresponding LEFT and RIGHT x
5656 // coordinate (which define the scanline).
5657 scanLimitMapL
[0] = double(x
[scanEdgeL
[1]] - x
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5658 scanLimitMapL
[1] = x
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanLimitMapL
[0];
5659 scanLimitMapR
[0] = double(x
[scanEdgeR
[1]] - x
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5660 scanLimitMapR
[1] = x
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanLimitMapR
[0];
5662 xa
= y
[1] * scanLimitMapL
[0] + scanLimitMapL
[1];
5663 xt
= y
[1] * scanLimitMapR
[0] + scanLimitMapR
[1];
5665 // I have "left" is to the right of "right".
5667 Guswap(scanEdgeL
[0], scanEdgeR
[0]);
5668 Guswap(scanEdgeL
[1], scanEdgeR
[1]);
5669 Guswap(scanLimitMapL
[0], scanLimitMapR
[0]);
5670 Guswap(scanLimitMapL
[1], scanLimitMapR
[1]);
5671 // FIXME I'm sure there is a more efficient way to check this.
5674 // Same game: we can linearly interpolate the color based on the
5675 // current y coordinate (that's correct for triangle
5676 // interpolation due to linearity. We could also have done it in
5677 // barycentric coordinates, but that's slightly more involved)
5678 scanColorMapL
[0] = (color
[scanEdgeL
[1]] - color
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5679 scanColorMapL
[1] = color
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanColorMapL
[0];
5680 scanColorMapR
[0] = (color
[scanEdgeR
[1]] - color
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5681 scanColorMapR
[1] = color
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanColorMapR
[0];
5683 hasFurtherSegment
= (y
[1] < y
[2]);
5684 scanLineOff
= y
[0] * rowSize
;
5686 for (int Y
= y
[0]; Y
<= y
[2]; ++Y
, scanLineOff
+= rowSize
) {
5687 if (hasFurtherSegment
&& Y
== y
[1]) {
5688 // SWEEP EVENT: we encountered the next segment.
5690 // switch to next segment, either at left end or at right
5692 if (scanEdgeL
[1] == 1) {
5695 scanLimitMapL
[0] = double(x
[scanEdgeL
[1]] - x
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5696 scanLimitMapL
[1] = x
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanLimitMapL
[0];
5698 scanColorMapL
[0] = (color
[scanEdgeL
[1]] - color
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5699 scanColorMapL
[1] = color
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanColorMapL
[0];
5700 } else if (scanEdgeR
[1] == 1) {
5703 scanLimitMapR
[0] = double(x
[scanEdgeR
[1]] - x
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5704 scanLimitMapR
[1] = x
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanLimitMapR
[0];
5706 scanColorMapR
[0] = (color
[scanEdgeR
[1]] - color
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5707 scanColorMapR
[1] = color
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanColorMapR
[0];
5709 assert( y
[scanEdgeL
[0]] < y
[scanEdgeL
[1]] );
5710 assert( y
[scanEdgeR
[0]] < y
[scanEdgeR
[1]] );
5711 hasFurtherSegment
= gFalse
;
5716 xa
= yt
* scanLimitMapL
[0] + scanLimitMapL
[1];
5717 xt
= yt
* scanLimitMapR
[0] + scanLimitMapR
[1];
5719 ca
= yt
* scanColorMapL
[0] + scanColorMapL
[1];
5720 ct
= yt
* scanColorMapR
[0] + scanColorMapR
[1];
5722 scanLimitL
= splashRound(xa
);
5723 scanLimitR
= splashRound(xt
);
5725 // Ok. Now: init the color interpolation depending on the X
5726 // coordinate inside of the current scanline:
5727 scanColorMap
[0] = (scanLimitR
== scanLimitL
) ? 0. : ((ct
- ca
) / (scanLimitR
- scanLimitL
));
5728 scanColorMap
[1] = ca
- scanLimitL
* scanColorMap
[0];
5730 // handled by clipping:
5731 // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
5732 assert(scanLimitL
<= scanLimitR
|| abs(scanLimitL
- scanLimitR
) <= 2); // allow rounding inaccuracies
5733 assert(scanLineOff
== Y
* rowSize
);
5735 colorinterp
= scanColorMap
[0] * scanLimitL
+ scanColorMap
[1];
5737 bitmapOff
= scanLineOff
+ scanLimitL
* colorComps
;
5738 for (int X
= scanLimitL
; X
<= scanLimitR
&& bitmapOff
+ colorComps
<= bitmapOffLimit
; ++X
, colorinterp
+= scanColorMap
[0], bitmapOff
+= colorComps
) {
5739 // FIXME : standard rectangular clipping can be done for a
5740 // complete scanline which is faster
5741 // --> see SplashClip and its methods
5742 if (!clip
->test(X
, Y
))
5745 assert(fabs(colorinterp
- (scanColorMap
[0] * X
+ scanColorMap
[1])) < 1e-10);
5746 assert(bitmapOff
== Y
* rowSize
+ colorComps
* X
&& scanLineOff
== Y
* rowSize
);
5748 shading
->getParameterizedColor(colorinterp
, bitmapMode
, &bitmapData
[bitmapOff
]);
5750 // make the shading visible.
5751 // Note that opacity is handled by the bDirectBlit stuff, see
5752 // above for comments and below for implementation.
5754 bitmapAlpha
[Y
* bitmapWidth
+ X
] = 255;
5763 // ok. Finalize the stuff by blitting the shading into the final
5764 // geometry, this time respecting the rendering pipe.
5765 int W
= blitTarget
->getWidth();
5766 int H
= blitTarget
->getHeight();
5769 for (int X
= 0; X
< W
; ++X
) {
5770 for (int Y
= 0; Y
< H
; ++Y
) {
5771 if (!bitmapAlpha
[Y
* bitmapWidth
+ X
])
5772 continue; // draw only parts of the shading!
5773 bitmapOff
= Y
* rowSize
+ colorComps
* X
;
5775 for (int m
= 0; m
< colorComps
; ++m
)
5776 cur
[m
] = bitmapData
[bitmapOff
+ m
];
5777 if (vectorAntialias
) {
5778 drawAAPixel(&pipe
, X
, Y
);
5780 drawPixel(&pipe
, X
, Y
, gTrue
); // no clipping - has already been done.
5792 SplashError
Splash::blitTransparent(SplashBitmap
*src
, int xSrc
, int ySrc
,
5793 int xDest
, int yDest
, int w
, int h
) {
5794 SplashColorPtr p
, sp
;
5796 int x
, y
, mask
, srcMask
;
5798 if (src
->mode
!= bitmap
->mode
) {
5799 return splashErrModeMismatch
;
5802 if (unlikely(!bitmap
->data
)) {
5803 return splashErrZeroImage
;
5806 switch (bitmap
->mode
) {
5807 case splashModeMono1
:
5808 for (y
= 0; y
< h
; ++y
) {
5809 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ (xDest
>> 3)];
5810 mask
= 0x80 >> (xDest
& 7);
5811 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ (xSrc
>> 3)];
5812 srcMask
= 0x80 >> (xSrc
& 7);
5813 for (x
= 0; x
< w
; ++x
) {
5814 if (*sp
& srcMask
) {
5819 if (!(mask
>>= 1)) {
5823 if (!(srcMask
>>= 1)) {
5830 case splashModeMono8
:
5831 for (y
= 0; y
< h
; ++y
) {
5832 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ xDest
];
5833 sp
= &src
->data
[(ySrc
+ y
) * bitmap
->rowSize
+ xSrc
];
5834 for (x
= 0; x
< w
; ++x
) {
5839 case splashModeRGB8
:
5840 case splashModeBGR8
:
5841 for (y
= 0; y
< h
; ++y
) {
5842 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 3 * xDest
];
5843 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ 3 * xSrc
];
5844 for (x
= 0; x
< w
; ++x
) {
5851 case splashModeXBGR8
:
5852 for (y
= 0; y
< h
; ++y
) {
5853 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 4 * xDest
];
5854 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ 4 * xSrc
];
5855 for (x
= 0; x
< w
; ++x
) {
5865 case splashModeCMYK8
:
5866 for (y
= 0; y
< h
; ++y
) {
5867 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 4 * xDest
];
5868 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ 4 * xSrc
];
5869 for (x
= 0; x
< w
; ++x
) {
5877 case splashModeDeviceN8
:
5878 for (y
= 0; y
< h
; ++y
) {
5879 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ (SPOT_NCOMPS
+4) * xDest
];
5880 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ (SPOT_NCOMPS
+4) * xSrc
];
5881 for (x
= 0; x
< w
; ++x
) {
5882 for (int cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
5890 if (bitmap
->alpha
) {
5891 for (y
= 0; y
< h
; ++y
) {
5892 q
= &bitmap
->alpha
[(yDest
+ y
) * bitmap
->width
+ xDest
];
5900 SplashPath
*Splash::makeStrokePath(SplashPath
*path
, SplashCoord w
,
5902 SplashPath
*pathIn
, *dashPath
, *pathOut
;
5903 SplashCoord d
, dx
, dy
, wdx
, wdy
, dxNext
, dyNext
, wdxNext
, wdyNext
;
5904 SplashCoord crossprod
, dotprod
, miter
, m
;
5905 GBool first
, last
, closed
;
5906 int subpathStart0
, subpathStart1
, seg
, i0
, i1
, j0
, j1
, k0
, k1
;
5907 int left0
, left1
, left2
, right0
, right1
, right2
, join0
, join1
, join2
;
5908 int leftFirst
, rightFirst
, firstPt
;
5910 pathOut
= new SplashPath();
5912 if (path
->length
== 0) {
5917 pathIn
= flattenPath(path
, state
->matrix
, state
->flatness
);
5918 if (state
->lineDashLength
> 0) {
5919 dashPath
= makeDashedPath(pathIn
);
5922 if (pathIn
->length
== 0) {
5931 subpathStart0
= subpathStart1
= 0; // make gcc happy
5932 seg
= 0; // make gcc happy
5933 closed
= gFalse
; // make gcc happy
5934 left0
= left1
= right0
= right1
= join0
= join1
= 0; // make gcc happy
5935 leftFirst
= rightFirst
= firstPt
= 0; // make gcc happy
5939 !(pathIn
->flags
[i1
] & splashPathLast
) &&
5940 i1
+ 1 < pathIn
->length
&&
5941 pathIn
->pts
[i1
+1].x
== pathIn
->pts
[i1
].x
&&
5942 pathIn
->pts
[i1
+1].y
== pathIn
->pts
[i1
].y
;
5945 while (i1
< pathIn
->length
) {
5946 if ((first
= pathIn
->flags
[i0
] & splashPathFirst
)) {
5950 closed
= pathIn
->flags
[i0
] & splashPathClosed
;
5953 if (j0
< pathIn
->length
) {
5955 !(pathIn
->flags
[j1
] & splashPathLast
) &&
5956 j1
+ 1 < pathIn
->length
&&
5957 pathIn
->pts
[j1
+1].x
== pathIn
->pts
[j1
].x
&&
5958 pathIn
->pts
[j1
+1].y
== pathIn
->pts
[j1
].y
;
5963 if (pathIn
->flags
[i1
] & splashPathLast
) {
5964 if (first
&& state
->lineCap
== splashLineCapRound
) {
5965 // special case: zero-length subpath with round line caps -->
5967 pathOut
->moveTo(pathIn
->pts
[i0
].x
+ (SplashCoord
)0.5 * w
,
5969 pathOut
->curveTo(pathIn
->pts
[i0
].x
+ (SplashCoord
)0.5 * w
,
5970 pathIn
->pts
[i0
].y
+ bezierCircle2
* w
,
5971 pathIn
->pts
[i0
].x
+ bezierCircle2
* w
,
5972 pathIn
->pts
[i0
].y
+ (SplashCoord
)0.5 * w
,
5974 pathIn
->pts
[i0
].y
+ (SplashCoord
)0.5 * w
);
5975 pathOut
->curveTo(pathIn
->pts
[i0
].x
- bezierCircle2
* w
,
5976 pathIn
->pts
[i0
].y
+ (SplashCoord
)0.5 * w
,
5977 pathIn
->pts
[i0
].x
- (SplashCoord
)0.5 * w
,
5978 pathIn
->pts
[i0
].y
+ bezierCircle2
* w
,
5979 pathIn
->pts
[i0
].x
- (SplashCoord
)0.5 * w
,
5981 pathOut
->curveTo(pathIn
->pts
[i0
].x
- (SplashCoord
)0.5 * w
,
5982 pathIn
->pts
[i0
].y
- bezierCircle2
* w
,
5983 pathIn
->pts
[i0
].x
- bezierCircle2
* w
,
5984 pathIn
->pts
[i0
].y
- (SplashCoord
)0.5 * w
,
5986 pathIn
->pts
[i0
].y
- (SplashCoord
)0.5 * w
);
5987 pathOut
->curveTo(pathIn
->pts
[i0
].x
+ bezierCircle2
* w
,
5988 pathIn
->pts
[i0
].y
- (SplashCoord
)0.5 * w
,
5989 pathIn
->pts
[i0
].x
+ (SplashCoord
)0.5 * w
,
5990 pathIn
->pts
[i0
].y
- bezierCircle2
* w
,
5991 pathIn
->pts
[i0
].x
+ (SplashCoord
)0.5 * w
,
5999 last
= pathIn
->flags
[j1
] & splashPathLast
;
6001 k0
= subpathStart1
+ 1;
6006 !(pathIn
->flags
[k1
] & splashPathLast
) &&
6007 k1
+ 1 < pathIn
->length
&&
6008 pathIn
->pts
[k1
+1].x
== pathIn
->pts
[k1
].x
&&
6009 pathIn
->pts
[k1
+1].y
== pathIn
->pts
[k1
].y
;
6012 // compute the deltas for segment (i1, j0)
6014 // the 1/d value can be small, which introduces significant
6015 // inaccuracies in fixed point mode
6016 d
= splashDist(pathIn
->pts
[i1
].x
, pathIn
->pts
[i1
].y
,
6017 pathIn
->pts
[j0
].x
, pathIn
->pts
[j0
].y
);
6018 dx
= (pathIn
->pts
[j0
].x
- pathIn
->pts
[i1
].x
) / d
;
6019 dy
= (pathIn
->pts
[j0
].y
- pathIn
->pts
[i1
].y
) / d
;
6021 d
= (SplashCoord
)1 / splashDist(pathIn
->pts
[i1
].x
, pathIn
->pts
[i1
].y
,
6022 pathIn
->pts
[j0
].x
, pathIn
->pts
[j0
].y
);
6023 dx
= d
* (pathIn
->pts
[j0
].x
- pathIn
->pts
[i1
].x
);
6024 dy
= d
* (pathIn
->pts
[j0
].y
- pathIn
->pts
[i1
].y
);
6026 wdx
= (SplashCoord
)0.5 * w
* dx
;
6027 wdy
= (SplashCoord
)0.5 * w
* dy
;
6029 // draw the start cap
6030 pathOut
->moveTo(pathIn
->pts
[i0
].x
- wdy
, pathIn
->pts
[i0
].y
+ wdx
);
6031 if (i0
== subpathStart0
) {
6032 firstPt
= pathOut
->length
- 1;
6034 if (first
&& !closed
) {
6035 switch (state
->lineCap
) {
6036 case splashLineCapButt
:
6037 pathOut
->lineTo(pathIn
->pts
[i0
].x
+ wdy
, pathIn
->pts
[i0
].y
- wdx
);
6039 case splashLineCapRound
:
6040 pathOut
->curveTo(pathIn
->pts
[i0
].x
- wdy
- bezierCircle
* wdx
,
6041 pathIn
->pts
[i0
].y
+ wdx
- bezierCircle
* wdy
,
6042 pathIn
->pts
[i0
].x
- wdx
- bezierCircle
* wdy
,
6043 pathIn
->pts
[i0
].y
- wdy
+ bezierCircle
* wdx
,
6044 pathIn
->pts
[i0
].x
- wdx
,
6045 pathIn
->pts
[i0
].y
- wdy
);
6046 pathOut
->curveTo(pathIn
->pts
[i0
].x
- wdx
+ bezierCircle
* wdy
,
6047 pathIn
->pts
[i0
].y
- wdy
- bezierCircle
* wdx
,
6048 pathIn
->pts
[i0
].x
+ wdy
- bezierCircle
* wdx
,
6049 pathIn
->pts
[i0
].y
- wdx
- bezierCircle
* wdy
,
6050 pathIn
->pts
[i0
].x
+ wdy
,
6051 pathIn
->pts
[i0
].y
- wdx
);
6053 case splashLineCapProjecting
:
6054 pathOut
->lineTo(pathIn
->pts
[i0
].x
- wdx
- wdy
,
6055 pathIn
->pts
[i0
].y
+ wdx
- wdy
);
6056 pathOut
->lineTo(pathIn
->pts
[i0
].x
- wdx
+ wdy
,
6057 pathIn
->pts
[i0
].y
- wdx
- wdy
);
6058 pathOut
->lineTo(pathIn
->pts
[i0
].x
+ wdy
,
6059 pathIn
->pts
[i0
].y
- wdx
);
6063 pathOut
->lineTo(pathIn
->pts
[i0
].x
+ wdy
, pathIn
->pts
[i0
].y
- wdx
);
6066 // draw the left side of the segment rectangle
6067 left2
= pathOut
->length
- 1;
6068 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
, pathIn
->pts
[j0
].y
- wdx
);
6071 if (last
&& !closed
) {
6072 switch (state
->lineCap
) {
6073 case splashLineCapButt
:
6074 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
, pathIn
->pts
[j0
].y
+ wdx
);
6076 case splashLineCapRound
:
6077 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ wdy
+ bezierCircle
* wdx
,
6078 pathIn
->pts
[j0
].y
- wdx
+ bezierCircle
* wdy
,
6079 pathIn
->pts
[j0
].x
+ wdx
+ bezierCircle
* wdy
,
6080 pathIn
->pts
[j0
].y
+ wdy
- bezierCircle
* wdx
,
6081 pathIn
->pts
[j0
].x
+ wdx
,
6082 pathIn
->pts
[j0
].y
+ wdy
);
6083 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ wdx
- bezierCircle
* wdy
,
6084 pathIn
->pts
[j0
].y
+ wdy
+ bezierCircle
* wdx
,
6085 pathIn
->pts
[j0
].x
- wdy
+ bezierCircle
* wdx
,
6086 pathIn
->pts
[j0
].y
+ wdx
+ bezierCircle
* wdy
,
6087 pathIn
->pts
[j0
].x
- wdy
,
6088 pathIn
->pts
[j0
].y
+ wdx
);
6090 case splashLineCapProjecting
:
6091 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
+ wdx
,
6092 pathIn
->pts
[j0
].y
- wdx
+ wdy
);
6093 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
+ wdx
,
6094 pathIn
->pts
[j0
].y
+ wdx
+ wdy
);
6095 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
,
6096 pathIn
->pts
[j0
].y
+ wdx
);
6100 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
, pathIn
->pts
[j0
].y
+ wdx
);
6103 // draw the right side of the segment rectangle
6104 // (NB: if stroke adjustment is enabled, the closepath operation MUST
6105 // add a segment because this segment is used for a hint)
6106 right2
= pathOut
->length
- 1;
6107 pathOut
->close(state
->strokeAdjust
);
6110 join2
= pathOut
->length
;
6111 if (!last
|| closed
) {
6113 // compute the deltas for segment (j1, k0)
6115 // the 1/d value can be small, which introduces significant
6116 // inaccuracies in fixed point mode
6117 d
= splashDist(pathIn
->pts
[j1
].x
, pathIn
->pts
[j1
].y
,
6118 pathIn
->pts
[k0
].x
, pathIn
->pts
[k0
].y
);
6119 dxNext
= (pathIn
->pts
[k0
].x
- pathIn
->pts
[j1
].x
) / d
;
6120 dyNext
= (pathIn
->pts
[k0
].y
- pathIn
->pts
[j1
].y
) / d
;
6122 d
= (SplashCoord
)1 / splashDist(pathIn
->pts
[j1
].x
, pathIn
->pts
[j1
].y
,
6123 pathIn
->pts
[k0
].x
, pathIn
->pts
[k0
].y
);
6124 dxNext
= d
* (pathIn
->pts
[k0
].x
- pathIn
->pts
[j1
].x
);
6125 dyNext
= d
* (pathIn
->pts
[k0
].y
- pathIn
->pts
[j1
].y
);
6127 wdxNext
= (SplashCoord
)0.5 * w
* dxNext
;
6128 wdyNext
= (SplashCoord
)0.5 * w
* dyNext
;
6130 // compute the join parameters
6131 crossprod
= dx
* dyNext
- dy
* dxNext
;
6132 dotprod
= -(dx
* dxNext
+ dy
* dyNext
);
6133 if (dotprod
> 0.9999) {
6134 // avoid a divide-by-zero -- set miter to something arbitrary
6135 // such that sqrt(miter) will exceed miterLimit (and m is never
6136 // used in that situation)
6137 // (note: the comparison value (0.9999) has to be less than
6138 // 1-epsilon, where epsilon is the smallest value
6139 // representable in the fixed point format)
6140 miter
= (state
->miterLimit
+ 1) * (state
->miterLimit
+ 1);
6143 miter
= (SplashCoord
)2 / ((SplashCoord
)1 - dotprod
);
6145 // this can happen because of floating point inaccuracies
6148 m
= splashSqrt(miter
- 1);
6152 if (state
->lineJoin
== splashLineJoinRound
) {
6153 pathOut
->moveTo(pathIn
->pts
[j0
].x
+ (SplashCoord
)0.5 * w
,
6155 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ (SplashCoord
)0.5 * w
,
6156 pathIn
->pts
[j0
].y
+ bezierCircle2
* w
,
6157 pathIn
->pts
[j0
].x
+ bezierCircle2
* w
,
6158 pathIn
->pts
[j0
].y
+ (SplashCoord
)0.5 * w
,
6160 pathIn
->pts
[j0
].y
+ (SplashCoord
)0.5 * w
);
6161 pathOut
->curveTo(pathIn
->pts
[j0
].x
- bezierCircle2
* w
,
6162 pathIn
->pts
[j0
].y
+ (SplashCoord
)0.5 * w
,
6163 pathIn
->pts
[j0
].x
- (SplashCoord
)0.5 * w
,
6164 pathIn
->pts
[j0
].y
+ bezierCircle2
* w
,
6165 pathIn
->pts
[j0
].x
- (SplashCoord
)0.5 * w
,
6167 pathOut
->curveTo(pathIn
->pts
[j0
].x
- (SplashCoord
)0.5 * w
,
6168 pathIn
->pts
[j0
].y
- bezierCircle2
* w
,
6169 pathIn
->pts
[j0
].x
- bezierCircle2
* w
,
6170 pathIn
->pts
[j0
].y
- (SplashCoord
)0.5 * w
,
6172 pathIn
->pts
[j0
].y
- (SplashCoord
)0.5 * w
);
6173 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ bezierCircle2
* w
,
6174 pathIn
->pts
[j0
].y
- (SplashCoord
)0.5 * w
,
6175 pathIn
->pts
[j0
].x
+ (SplashCoord
)0.5 * w
,
6176 pathIn
->pts
[j0
].y
- bezierCircle2
* w
,
6177 pathIn
->pts
[j0
].x
+ (SplashCoord
)0.5 * w
,
6181 pathOut
->moveTo(pathIn
->pts
[j0
].x
, pathIn
->pts
[j0
].y
);
6184 if (crossprod
< 0) {
6185 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdyNext
,
6186 pathIn
->pts
[j0
].y
+ wdxNext
);
6187 // miter join inside limit
6188 if (state
->lineJoin
== splashLineJoinMiter
&&
6189 splashSqrt(miter
) <= state
->miterLimit
) {
6190 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
+ wdx
* m
,
6191 pathIn
->pts
[j0
].y
+ wdx
+ wdy
* m
);
6192 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
,
6193 pathIn
->pts
[j0
].y
+ wdx
);
6194 // bevel join or miter join outside limit
6196 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
,
6197 pathIn
->pts
[j0
].y
+ wdx
);
6202 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
,
6203 pathIn
->pts
[j0
].y
- wdx
);
6204 // miter join inside limit
6205 if (state
->lineJoin
== splashLineJoinMiter
&&
6206 splashSqrt(miter
) <= state
->miterLimit
) {
6207 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
+ wdx
* m
,
6208 pathIn
->pts
[j0
].y
- wdx
+ wdy
* m
);
6209 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdyNext
,
6210 pathIn
->pts
[j0
].y
- wdxNext
);
6211 // bevel join or miter join outside limit
6213 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdyNext
,
6214 pathIn
->pts
[j0
].y
- wdxNext
);
6222 // add stroke adjustment hints
6223 if (state
->strokeAdjust
) {
6224 if (seg
== 0 && !closed
) {
6225 if (state
->lineCap
== splashLineCapButt
) {
6226 pathOut
->addStrokeAdjustHint(firstPt
, left2
+ 1,
6227 firstPt
, firstPt
+ 1);
6229 pathOut
->addStrokeAdjustHint(firstPt
, left2
+ 1,
6230 left2
+ 1, left2
+ 2);
6232 } else if (state
->lineCap
== splashLineCapProjecting
) {
6234 pathOut
->addStrokeAdjustHint(firstPt
+ 1, left2
+ 2,
6235 firstPt
+ 1, firstPt
+ 2);
6236 pathOut
->addStrokeAdjustHint(firstPt
+ 1, left2
+ 2,
6237 left2
+ 2, left2
+ 3);
6239 pathOut
->addStrokeAdjustHint(firstPt
+ 1, left2
+ 1,
6240 firstPt
+ 1, firstPt
+ 2);
6246 pathOut
->addStrokeAdjustHint(left1
, right1
, left0
+ 1, right0
);
6247 pathOut
->addStrokeAdjustHint(left1
, right1
, join0
, left2
);
6249 pathOut
->addStrokeAdjustHint(left1
, right1
, firstPt
, left2
);
6251 pathOut
->addStrokeAdjustHint(left1
, right1
, right2
+ 1, right2
+ 1);
6261 rightFirst
= right2
;
6265 pathOut
->addStrokeAdjustHint(left1
, right1
, left0
+ 1, right0
);
6266 pathOut
->addStrokeAdjustHint(left1
, right1
,
6267 join0
, pathOut
->length
- 1);
6269 pathOut
->addStrokeAdjustHint(left1
, right1
,
6270 firstPt
, pathOut
->length
- 1);
6273 pathOut
->addStrokeAdjustHint(left1
, right1
, firstPt
, leftFirst
);
6274 pathOut
->addStrokeAdjustHint(left1
, right1
,
6275 rightFirst
+ 1, rightFirst
+ 1);
6276 pathOut
->addStrokeAdjustHint(leftFirst
, rightFirst
,
6278 pathOut
->addStrokeAdjustHint(leftFirst
, rightFirst
,
6279 join1
, pathOut
->length
- 1);
6281 if (!closed
&& seg
> 0) {
6282 if (state
->lineCap
== splashLineCapButt
) {
6283 pathOut
->addStrokeAdjustHint(left1
- 1, left1
+ 1,
6284 left1
+ 1, left1
+ 2);
6285 } else if (state
->lineCap
== splashLineCapProjecting
) {
6286 pathOut
->addStrokeAdjustHint(left1
- 1, left1
+ 2,
6287 left1
+ 2, left1
+ 3);
6298 if (pathIn
!= path
) {
6305 void Splash::dumpPath(SplashPath
*path
) {
6308 for (i
= 0; i
< path
->length
; ++i
) {
6309 printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
6310 i
, (double)path
->pts
[i
].x
, (double)path
->pts
[i
].y
,
6311 (path
->flags
[i
] & splashPathFirst
) ? " first" : "",
6312 (path
->flags
[i
] & splashPathLast
) ? " last" : "",
6313 (path
->flags
[i
] & splashPathClosed
) ? " closed" : "",
6314 (path
->flags
[i
] & splashPathCurve
) ? " curve" : "");
6318 void Splash::dumpXPath(SplashXPath
*path
) {
6321 for (i
= 0; i
< path
->length
; ++i
) {
6322 printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n",
6323 i
, (double)path
->segs
[i
].x0
, (double)path
->segs
[i
].y0
,
6324 (double)path
->segs
[i
].x1
, (double)path
->segs
[i
].y1
,
6325 (path
->segs
[i
].flags
& splashXPathHoriz
) ? "H" : " ",
6326 (path
->segs
[i
].flags
& splashXPathVert
) ? "V" : " ",
6327 (path
->segs
[i
].flags
& splashXPathFlip
) ? "P" : " ");
6331 SplashError
Splash::shadedFill(SplashPath
*path
, GBool hasBBox
,
6332 SplashPattern
*pattern
) {
6335 SplashXPathScanner
*scanner
;
6336 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
6337 SplashClipResult clipRes
;
6339 if (vectorAntialias
&& aaBuf
== NULL
) { // should not happen, but to be secure
6340 return splashErrGeneric
;
6342 if (path
->length
== 0) {
6343 return splashErrEmptyPath
;
6345 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
);
6346 if (vectorAntialias
) {
6350 yMinI
= state
->clip
->getYMinI();
6351 yMaxI
= state
->clip
->getYMaxI();
6352 if (vectorAntialias
&& !inShading
) {
6353 yMinI
= yMinI
* splashAASize
;
6354 yMaxI
= (yMaxI
+ 1) * splashAASize
- 1;
6356 scanner
= new SplashXPathScanner(xPath
, gFalse
, yMinI
, yMaxI
);
6358 // get the min and max x and y values
6359 if (vectorAntialias
) {
6360 scanner
->getBBoxAA(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
6362 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
6366 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
)) != splashClipAllOutside
) {
6367 // limit the y range
6368 if (yMinI
< state
->clip
->getYMinI()) {
6369 yMinI
= state
->clip
->getYMinI();
6371 if (yMaxI
> state
->clip
->getYMaxI()) {
6372 yMaxI
= state
->clip
->getYMaxI();
6375 pipeInit(&pipe
, 0, yMinI
, pattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), vectorAntialias
&& !hasBBox
, gFalse
);
6378 if (vectorAntialias
) {
6379 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
6380 scanner
->renderAALine(aaBuf
, &x0
, &x1
, y
);
6381 if (clipRes
!= splashClipAllInside
) {
6382 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
);
6384 #if splashAASize == 4
6385 if (!hasBBox
&& y
> yMinI
&& y
< yMaxI
) {
6386 // correct shape on left side if clip is
6387 // vertical through the middle of shading:
6388 Guchar
*p0
, *p1
, *p2
, *p3
;
6389 Guchar c1
, c2
, c3
, c4
;
6390 p0
= aaBuf
->getDataPtr() + (x0
>> 1);
6391 p1
= p0
+ aaBuf
->getRowSize();
6392 p2
= p1
+ aaBuf
->getRowSize();
6393 p3
= p2
+ aaBuf
->getRowSize();
6395 c1
= (*p0
& 0x0f); c2
=(*p1
& 0x0f); c3
= (*p2
& 0x0f) ; c4
= (*p3
& 0x0f);
6397 c1
= (*p0
>> 4); c2
= (*p1
>> 4); c3
= (*p2
>> 4); c4
= (*p3
>> 4);
6399 if ( (c1
& 0x03) == 0x03 && (c2
& 0x03) == 0x03 && (c3
& 0x03) == 0x03 && (c4
& 0x03) == 0x03
6400 && c1
== c2
&& c2
== c3
&& c3
== c4
&&
6401 pattern
->testPosition(x0
- 1, y
) )
6403 Guchar shapeCorrection
= (x0
& 1) ? 0x0f : 0xf0;
6404 *p0
|= shapeCorrection
;
6405 *p1
|= shapeCorrection
;
6406 *p2
|= shapeCorrection
;
6407 *p3
|= shapeCorrection
;
6409 // correct shape on right side if clip is
6410 // through the middle of shading:
6411 p0
= aaBuf
->getDataPtr() + (x1
>> 1);
6412 p1
= p0
+ aaBuf
->getRowSize();
6413 p2
= p1
+ aaBuf
->getRowSize();
6414 p3
= p2
+ aaBuf
->getRowSize();
6416 c1
= (*p0
& 0x0f); c2
=(*p1
& 0x0f); c3
= (*p2
& 0x0f) ; c4
= (*p3
& 0x0f);
6418 c1
= (*p0
>> 4); c2
= (*p1
>> 4); c3
= (*p2
>> 4); c4
= (*p3
>> 4);
6421 if ( (c1
& 0xc) == 0x0c && (c2
& 0x0c) == 0x0c && (c3
& 0x0c) == 0x0c && (c4
& 0x0c) == 0x0c
6422 && c1
== c2
&& c2
== c3
&& c3
== c4
&&
6423 pattern
->testPosition(x1
+ 1, y
) )
6425 Guchar shapeCorrection
= (x1
& 1) ? 0x0f : 0xf0;
6426 *p0
|= shapeCorrection
;
6427 *p1
|= shapeCorrection
;
6428 *p2
|= shapeCorrection
;
6429 *p3
|= shapeCorrection
;
6433 drawAALine(&pipe
, x0
, x1
, y
);
6436 SplashClipResult clipRes2
;
6437 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
6438 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
6439 if (clipRes
== splashClipAllInside
) {
6440 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
6442 // limit the x range
6443 if (x0
< state
->clip
->getXMinI()) {
6444 x0
= state
->clip
->getXMinI();
6446 if (x1
> state
->clip
->getXMaxI()) {
6447 x1
= state
->clip
->getXMaxI();
6449 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
6450 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
6456 opClipRes
= clipRes
;