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
= (state
->multiplyPatternAlpha
) ? alpha
* state
->patternStrokeAlpha
: alpha
;
1758 void Splash::setFillAlpha(SplashCoord alpha
) {
1759 state
->fillAlpha
= (state
->multiplyPatternAlpha
) ? alpha
* state
->patternFillAlpha
: alpha
;
1762 void Splash::setPatternAlpha(SplashCoord strokeAlpha
, SplashCoord fillAlpha
) {
1763 state
->patternStrokeAlpha
= strokeAlpha
;
1764 state
->patternFillAlpha
= fillAlpha
;
1765 state
->multiplyPatternAlpha
= gTrue
;
1768 void Splash::clearPatternAlpha() {
1769 state
->patternStrokeAlpha
= 1;
1770 state
->patternFillAlpha
= 1;
1771 state
->multiplyPatternAlpha
= gFalse
;
1774 void Splash::setFillOverprint(GBool fop
) {
1775 state
->fillOverprint
= fop
;
1778 void Splash::setStrokeOverprint(GBool gop
) {
1779 state
->strokeOverprint
= gop
;
1782 void Splash::setOverprintMode(int opm
) {
1783 state
->overprintMode
= opm
;
1786 void Splash::setLineWidth(SplashCoord lineWidth
) {
1787 state
->lineWidth
= lineWidth
;
1790 void Splash::setLineCap(int lineCap
) {
1791 state
->lineCap
= lineCap
;
1794 void Splash::setLineJoin(int lineJoin
) {
1795 state
->lineJoin
= lineJoin
;
1798 void Splash::setMiterLimit(SplashCoord miterLimit
) {
1799 state
->miterLimit
= miterLimit
;
1802 void Splash::setFlatness(SplashCoord flatness
) {
1804 state
->flatness
= 1;
1806 state
->flatness
= flatness
;
1810 void Splash::setLineDash(SplashCoord
*lineDash
, int lineDashLength
,
1811 SplashCoord lineDashPhase
) {
1812 state
->setLineDash(lineDash
, lineDashLength
, lineDashPhase
);
1815 void Splash::setStrokeAdjust(GBool strokeAdjust
) {
1816 state
->strokeAdjust
= strokeAdjust
;
1819 void Splash::clipResetToRect(SplashCoord x0
, SplashCoord y0
,
1820 SplashCoord x1
, SplashCoord y1
) {
1821 state
->clip
->resetToRect(x0
, y0
, x1
, y1
);
1824 SplashError
Splash::clipToRect(SplashCoord x0
, SplashCoord y0
,
1825 SplashCoord x1
, SplashCoord y1
) {
1826 return state
->clip
->clipToRect(x0
, y0
, x1
, y1
);
1829 SplashError
Splash::clipToPath(SplashPath
*path
, GBool eo
) {
1830 return state
->clip
->clipToPath(path
, state
->matrix
, state
->flatness
, eo
);
1833 void Splash::setSoftMask(SplashBitmap
*softMask
) {
1834 state
->setSoftMask(softMask
);
1837 void Splash::setInNonIsolatedGroup(SplashBitmap
*alpha0BitmapA
,
1838 int alpha0XA
, int alpha0YA
) {
1839 alpha0Bitmap
= alpha0BitmapA
;
1842 state
->inNonIsolatedGroup
= gTrue
;
1845 void Splash::setTransfer(Guchar
*red
, Guchar
*green
, Guchar
*blue
,
1847 state
->setTransfer(red
, green
, blue
, gray
);
1850 void Splash::setOverprintMask(Guint overprintMask
, GBool additive
) {
1851 state
->overprintMask
= overprintMask
;
1852 state
->overprintAdditive
= additive
;
1855 //------------------------------------------------------------------------
1856 // state save/restore
1857 //------------------------------------------------------------------------
1859 void Splash::saveState() {
1860 SplashState
*newState
;
1862 newState
= state
->copy();
1863 newState
->next
= state
;
1867 SplashError
Splash::restoreState() {
1868 SplashState
*oldState
;
1871 return splashErrNoSave
;
1874 state
= state
->next
;
1879 //------------------------------------------------------------------------
1880 // drawing operations
1881 //------------------------------------------------------------------------
1883 void Splash::clear(SplashColorPtr color
, Guchar alpha
) {
1884 SplashColorPtr row
, p
;
1888 switch (bitmap
->mode
) {
1889 case splashModeMono1
:
1890 mono
= (color
[0] & 0x80) ? 0xff : 0x00;
1891 if (bitmap
->rowSize
< 0) {
1892 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1893 mono
, -bitmap
->rowSize
* bitmap
->height
);
1895 memset(bitmap
->data
, mono
, bitmap
->rowSize
* bitmap
->height
);
1898 case splashModeMono8
:
1899 if (bitmap
->rowSize
< 0) {
1900 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1901 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1903 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1906 case splashModeRGB8
:
1907 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1908 if (bitmap
->rowSize
< 0) {
1909 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1910 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1912 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1916 for (y
= 0; y
< bitmap
->height
; ++y
) {
1918 for (x
= 0; x
< bitmap
->width
; ++x
) {
1923 row
+= bitmap
->rowSize
;
1927 case splashModeXBGR8
:
1928 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1929 if (bitmap
->rowSize
< 0) {
1930 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1931 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1933 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1937 for (y
= 0; y
< bitmap
->height
; ++y
) {
1939 for (x
= 0; x
< bitmap
->width
; ++x
) {
1945 row
+= bitmap
->rowSize
;
1949 case splashModeBGR8
:
1950 if (color
[0] == color
[1] && color
[1] == color
[2]) {
1951 if (bitmap
->rowSize
< 0) {
1952 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1953 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1955 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1959 for (y
= 0; y
< bitmap
->height
; ++y
) {
1961 for (x
= 0; x
< bitmap
->width
; ++x
) {
1966 row
+= bitmap
->rowSize
;
1971 case splashModeCMYK8
:
1972 if (color
[0] == color
[1] && color
[1] == color
[2] && color
[2] == color
[3]) {
1973 if (bitmap
->rowSize
< 0) {
1974 memset(bitmap
->data
+ bitmap
->rowSize
* (bitmap
->height
- 1),
1975 color
[0], -bitmap
->rowSize
* bitmap
->height
);
1977 memset(bitmap
->data
, color
[0], bitmap
->rowSize
* bitmap
->height
);
1981 for (y
= 0; y
< bitmap
->height
; ++y
) {
1983 for (x
= 0; x
< bitmap
->width
; ++x
) {
1989 row
+= bitmap
->rowSize
;
1993 case splashModeDeviceN8
:
1995 for (y
= 0; y
< bitmap
->height
; ++y
) {
1997 for (x
= 0; x
< bitmap
->width
; ++x
) {
1998 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
2001 row
+= bitmap
->rowSize
;
2007 if (bitmap
->alpha
) {
2008 memset(bitmap
->alpha
, alpha
, bitmap
->width
* bitmap
->height
);
2013 updateModX(bitmap
->width
- 1);
2014 updateModY(bitmap
->height
- 1);
2017 SplashError
Splash::stroke(SplashPath
*path
) {
2018 SplashPath
*path2
, *dPath
;
2019 SplashCoord d1
, d2
, t1
, t2
, w
;
2022 printf("stroke [dash:%d] [width:%.2f]:\n",
2023 state
->lineDashLength
, (double)state
->lineWidth
);
2026 opClipRes
= splashClipAllOutside
;
2027 if (path
->length
== 0) {
2028 return splashErrEmptyPath
;
2030 path2
= flattenPath(path
, state
->matrix
, state
->flatness
);
2031 if (state
->lineDashLength
> 0) {
2032 dPath
= makeDashedPath(path2
);
2035 if (path2
->length
== 0) {
2037 return splashErrEmptyPath
;
2041 // transform a unit square, and take the half the max of the two
2042 // diagonals; the product of this number and the line width is the
2043 // (approximate) transformed line width
2044 t1
= state
->matrix
[0] + state
->matrix
[2];
2045 t2
= state
->matrix
[1] + state
->matrix
[3];
2046 d1
= t1
* t1
+ t2
* t2
;
2047 t1
= state
->matrix
[0] - state
->matrix
[2];
2048 t2
= state
->matrix
[1] - state
->matrix
[3];
2049 d2
= t1
* t1
+ t2
* t2
;
2055 d1
* state
->lineWidth
* state
->lineWidth
< minLineWidth
* minLineWidth
) {
2056 w
= minLineWidth
/ splashSqrt(d1
);
2057 strokeWide(path2
, w
);
2058 } else if (bitmap
->mode
== splashModeMono1
) {
2059 // this gets close to Adobe's behavior in mono mode
2060 if (d1
* state
->lineWidth
<= 2) {
2061 strokeNarrow(path2
);
2063 strokeWide(path2
, state
->lineWidth
);
2066 if (state
->lineWidth
== 0) {
2067 strokeNarrow(path2
);
2069 strokeWide(path2
, state
->lineWidth
);
2077 void Splash::strokeNarrow(SplashPath
*path
) {
2080 SplashXPathSeg
*seg
;
2081 int x0
, x1
, y0
, y1
, xa
, xb
, y
;
2083 SplashClipResult clipRes
;
2087 nClipRes
[0] = nClipRes
[1] = nClipRes
[2] = 0;
2089 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gFalse
);
2091 pipeInit(&pipe
, 0, 0, state
->strokePattern
, NULL
,
2092 (Guchar
)splashRound(state
->strokeAlpha
* 255),
2095 for (i
= 0, seg
= xPath
->segs
; i
< xPath
->length
; ++i
, ++seg
) {
2096 if (seg
->y0
<= seg
->y1
) {
2097 y0
= splashFloor(seg
->y0
);
2098 y1
= splashFloor(seg
->y1
);
2099 x0
= splashFloor(seg
->x0
);
2100 x1
= splashFloor(seg
->x1
);
2102 y0
= splashFloor(seg
->y1
);
2103 y1
= splashFloor(seg
->y0
);
2104 x0
= splashFloor(seg
->x1
);
2105 x1
= splashFloor(seg
->x0
);
2107 if ((clipRes
= state
->clip
->testRect(x0
<= x1
? x0
: x1
, y0
,
2108 x0
<= x1
? x1
: x0
, y1
))
2109 != splashClipAllOutside
) {
2112 drawSpan(&pipe
, x0
, x1
, y0
, clipRes
== splashClipAllInside
);
2114 drawSpan(&pipe
, x1
, x0
, y0
, clipRes
== splashClipAllInside
);
2118 if (y0
< state
->clip
->getYMinI()) {
2119 y0
= state
->clip
->getYMinI();
2120 x0
= splashFloor(seg
->x0
+ ((SplashCoord
)y0
- seg
->y0
) * dxdy
);
2122 if (y1
> state
->clip
->getYMaxI()) {
2123 y1
= state
->clip
->getYMaxI();
2124 x1
= splashFloor(seg
->x0
+ ((SplashCoord
)y1
- seg
->y0
) * dxdy
);
2128 for (y
= y0
; y
<= y1
; ++y
) {
2130 xb
= splashFloor(seg
->x0
+
2131 ((SplashCoord
)y
+ 1 - seg
->y0
) * dxdy
);
2136 drawPixel(&pipe
, xa
, y
, clipRes
== splashClipAllInside
);
2138 drawSpan(&pipe
, xa
, xb
- 1, y
, clipRes
== splashClipAllInside
);
2144 for (y
= y0
; y
<= y1
; ++y
) {
2146 xb
= splashFloor(seg
->x0
+
2147 ((SplashCoord
)y
+ 1 - seg
->y0
) * dxdy
);
2152 drawPixel(&pipe
, xa
, y
, clipRes
== splashClipAllInside
);
2154 drawSpan(&pipe
, xb
+ 1, xa
, y
, clipRes
== splashClipAllInside
);
2161 ++nClipRes
[clipRes
];
2163 if (nClipRes
[splashClipPartial
] ||
2164 (nClipRes
[splashClipAllInside
] && nClipRes
[splashClipAllOutside
])) {
2165 opClipRes
= splashClipPartial
;
2166 } else if (nClipRes
[splashClipAllInside
]) {
2167 opClipRes
= splashClipAllInside
;
2169 opClipRes
= splashClipAllOutside
;
2175 void Splash::strokeWide(SplashPath
*path
, SplashCoord w
) {
2178 path2
= makeStrokePath(path
, w
, gFalse
);
2179 fillWithPattern(path2
, gFalse
, state
->strokePattern
, state
->strokeAlpha
);
2183 SplashPath
*Splash::flattenPath(SplashPath
*path
, SplashCoord
*matrix
,
2184 SplashCoord flatness
) {
2186 SplashCoord flatness2
;
2190 fPath
= new SplashPath();
2192 flatness2
= flatness
;
2194 flatness2
= flatness
* flatness
;
2197 while (i
< path
->length
) {
2198 flag
= path
->flags
[i
];
2199 if (flag
& splashPathFirst
) {
2200 fPath
->moveTo(path
->pts
[i
].x
, path
->pts
[i
].y
);
2203 if (flag
& splashPathCurve
) {
2204 flattenCurve(path
->pts
[i
-1].x
, path
->pts
[i
-1].y
,
2205 path
->pts
[i
].x
, path
->pts
[i
].y
,
2206 path
->pts
[i
+1].x
, path
->pts
[i
+1].y
,
2207 path
->pts
[i
+2].x
, path
->pts
[i
+2].y
,
2208 matrix
, flatness2
, fPath
);
2211 fPath
->lineTo(path
->pts
[i
].x
, path
->pts
[i
].y
);
2214 if (path
->flags
[i
-1] & splashPathClosed
) {
2222 void Splash::flattenCurve(SplashCoord x0
, SplashCoord y0
,
2223 SplashCoord x1
, SplashCoord y1
,
2224 SplashCoord x2
, SplashCoord y2
,
2225 SplashCoord x3
, SplashCoord y3
,
2226 SplashCoord
*matrix
, SplashCoord flatness2
,
2227 SplashPath
*fPath
) {
2228 SplashCoord cx
[splashMaxCurveSplits
+ 1][3];
2229 SplashCoord cy
[splashMaxCurveSplits
+ 1][3];
2230 int cNext
[splashMaxCurveSplits
+ 1];
2231 SplashCoord xl0
, xl1
, xl2
, xr0
, xr1
, xr2
, xr3
, xx1
, xx2
, xh
;
2232 SplashCoord yl0
, yl1
, yl2
, yr0
, yr1
, yr2
, yr3
, yy1
, yy2
, yh
;
2233 SplashCoord dx
, dy
, mx
, my
, tx
, ty
, d1
, d2
;
2238 p2
= splashMaxCurveSplits
;
2239 cx
[p1
][0] = x0
; cy
[p1
][0] = y0
;
2240 cx
[p1
][1] = x1
; cy
[p1
][1] = y1
;
2241 cx
[p1
][2] = x2
; cy
[p1
][2] = y2
;
2242 cx
[p2
][0] = x3
; cy
[p2
][0] = y3
;
2245 while (p1
< splashMaxCurveSplits
) {
2247 // get the next segment
2248 xl0
= cx
[p1
][0]; yl0
= cy
[p1
][0];
2249 xx1
= cx
[p1
][1]; yy1
= cy
[p1
][1];
2250 xx2
= cx
[p1
][2]; yy2
= cy
[p1
][2];
2252 xr3
= cx
[p2
][0]; yr3
= cy
[p2
][0];
2254 // compute the distances (in device space) from the control points
2255 // to the midpoint of the straight line (this is a bit of a hack,
2256 // but it's much faster than computing the actual distances to the
2258 transform(matrix
, (xl0
+ xr3
) * 0.5, (yl0
+ yr3
) * 0.5, &mx
, &my
);
2259 transform(matrix
, xx1
, yy1
, &tx
, &ty
);
2261 d1
= splashDist(tx
, ty
, mx
, my
);
2267 transform(matrix
, xx2
, yy2
, &tx
, &ty
);
2269 d2
= splashDist(tx
, ty
, mx
, my
);
2276 // if the curve is flat enough, or no more subdivisions are
2277 // allowed, add the straight line segment
2278 if (p2
- p1
== 1 || (d1
<= flatness2
&& d2
<= flatness2
)) {
2279 fPath
->lineTo(xr3
, yr3
);
2282 // otherwise, subdivide the curve
2284 xl1
= splashAvg(xl0
, xx1
);
2285 yl1
= splashAvg(yl0
, yy1
);
2286 xh
= splashAvg(xx1
, xx2
);
2287 yh
= splashAvg(yy1
, yy2
);
2288 xl2
= splashAvg(xl1
, xh
);
2289 yl2
= splashAvg(yl1
, yh
);
2290 xr2
= splashAvg(xx2
, xr3
);
2291 yr2
= splashAvg(yy2
, yr3
);
2292 xr1
= splashAvg(xh
, xr2
);
2293 yr1
= splashAvg(yh
, yr2
);
2294 xr0
= splashAvg(xl2
, xr1
);
2295 yr0
= splashAvg(yl2
, yr1
);
2296 // add the new subdivision points
2298 cx
[p1
][1] = xl1
; cy
[p1
][1] = yl1
;
2299 cx
[p1
][2] = xl2
; cy
[p1
][2] = yl2
;
2301 cx
[p3
][0] = xr0
; cy
[p3
][0] = yr0
;
2302 cx
[p3
][1] = xr1
; cy
[p3
][1] = yr1
;
2303 cx
[p3
][2] = xr2
; cy
[p3
][2] = yr2
;
2309 SplashPath
*Splash::makeDashedPath(SplashPath
*path
) {
2311 SplashCoord lineDashTotal
;
2312 SplashCoord lineDashStartPhase
, lineDashDist
, segLen
;
2313 SplashCoord x0
, y0
, x1
, y1
, xa
, ya
;
2314 GBool lineDashStartOn
, lineDashOn
, newPath
;
2315 int lineDashStartIdx
, lineDashIdx
;
2319 for (i
= 0; i
< state
->lineDashLength
; ++i
) {
2320 lineDashTotal
+= state
->lineDash
[i
];
2322 // Acrobat simply draws nothing if the dash array is [0]
2323 if (lineDashTotal
== 0) {
2324 return new SplashPath();
2326 lineDashStartPhase
= state
->lineDashPhase
;
2327 i
= splashFloor(lineDashStartPhase
/ lineDashTotal
);
2328 lineDashStartPhase
-= (SplashCoord
)i
* lineDashTotal
;
2329 lineDashStartOn
= gTrue
;
2330 lineDashStartIdx
= 0;
2331 if (lineDashStartPhase
> 0) {
2332 while (lineDashStartIdx
< state
->lineDashLength
&& lineDashStartPhase
>= state
->lineDash
[lineDashStartIdx
]) {
2333 lineDashStartOn
= !lineDashStartOn
;
2334 lineDashStartPhase
-= state
->lineDash
[lineDashStartIdx
];
2337 if (unlikely(lineDashStartIdx
== state
->lineDashLength
)) {
2338 return new SplashPath();
2342 dPath
= new SplashPath();
2344 // process each subpath
2346 while (i
< path
->length
) {
2348 // find the end of the subpath
2350 j
< path
->length
- 1 && !(path
->flags
[j
] & splashPathLast
);
2353 // initialize the dash parameters
2354 lineDashOn
= lineDashStartOn
;
2355 lineDashIdx
= lineDashStartIdx
;
2356 lineDashDist
= state
->lineDash
[lineDashIdx
] - lineDashStartPhase
;
2358 // process each segment of the subpath
2360 for (k
= i
; k
< j
; ++k
) {
2363 x0
= path
->pts
[k
].x
;
2364 y0
= path
->pts
[k
].y
;
2365 x1
= path
->pts
[k
+1].x
;
2366 y1
= path
->pts
[k
+1].y
;
2367 segLen
= splashDist(x0
, y0
, x1
, y1
);
2369 // process the segment
2370 while (segLen
> 0) {
2372 if (lineDashDist
>= segLen
) {
2375 dPath
->moveTo(x0
, y0
);
2378 dPath
->lineTo(x1
, y1
);
2380 lineDashDist
-= segLen
;
2384 xa
= x0
+ (lineDashDist
/ segLen
) * (x1
- x0
);
2385 ya
= y0
+ (lineDashDist
/ segLen
) * (y1
- y0
);
2388 dPath
->moveTo(x0
, y0
);
2391 dPath
->lineTo(xa
, ya
);
2395 segLen
-= lineDashDist
;
2399 // get the next entry in the dash array
2400 if (lineDashDist
<= 0) {
2401 lineDashOn
= !lineDashOn
;
2402 if (++lineDashIdx
== state
->lineDashLength
) {
2405 lineDashDist
= state
->lineDash
[lineDashIdx
];
2413 if (dPath
->length
== 0) {
2414 GBool allSame
= gTrue
;
2415 for (int i
= 0; allSame
&& i
< path
->length
- 1; ++i
) {
2416 allSame
= path
->pts
[i
].x
== path
->pts
[i
+ 1].x
&& path
->pts
[i
].y
== path
->pts
[i
+ 1].y
;
2419 x0
= path
->pts
[0].x
;
2420 y0
= path
->pts
[0].y
;
2421 dPath
->moveTo(x0
, y0
);
2422 dPath
->lineTo(x0
, y0
);
2429 SplashError
Splash::fill(SplashPath
*path
, GBool eo
) {
2431 printf("fill [eo:%d]:\n", eo
);
2434 return fillWithPattern(path
, eo
, state
->fillPattern
, state
->fillAlpha
);
2437 inline void Splash::getBBoxFP(SplashPath
*path
, SplashCoord
*xMinA
, SplashCoord
*yMinA
,
2438 SplashCoord
*xMaxA
, SplashCoord
*yMaxA
) {
2439 SplashCoord xMinFP
, yMinFP
, xMaxFP
, yMaxFP
, tx
, ty
;
2441 // make compiler happy:
2442 xMinFP
= xMaxFP
= yMinFP
= yMaxFP
= 0;
2443 for (int i
= 0; i
< path
->length
; ++i
) {
2444 transform(state
->matrix
, path
->pts
[i
].x
, path
->pts
[i
].y
, &tx
, &ty
);
2446 xMinFP
= xMaxFP
= tx
;
2447 yMinFP
= yMaxFP
= ty
;
2449 if (tx
< xMinFP
) xMinFP
= tx
;
2450 if (tx
> xMaxFP
) xMaxFP
= tx
;
2451 if (ty
< yMinFP
) yMinFP
= ty
;
2452 if (ty
> yMaxFP
) yMaxFP
= ty
;
2462 SplashError
Splash::fillWithPattern(SplashPath
*path
, GBool eo
,
2463 SplashPattern
*pattern
,
2464 SplashCoord alpha
) {
2467 SplashXPathScanner
*scanner
;
2468 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
2469 SplashClipResult clipRes
, clipRes2
;
2470 GBool adjustLine
= gFalse
;
2473 if (path
->length
== 0) {
2474 return splashErrEmptyPath
;
2476 if (pathAllOutside(path
)) {
2477 opClipRes
= splashClipAllOutside
;
2481 // add stroke adjustment hints for filled rectangles -- this only
2482 // applies to paths that consist of a single subpath
2483 // (this appears to match Acrobat's behavior)
2484 if (state
->strokeAdjust
&& !path
->hints
) {
2486 n
= path
->getLength();
2488 !(path
->flags
[0] & splashPathClosed
) &&
2489 !(path
->flags
[1] & splashPathLast
) &&
2490 !(path
->flags
[2] & splashPathLast
)) {
2492 path
->addStrokeAdjustHint(0, 2, 0, 4);
2493 path
->addStrokeAdjustHint(1, 3, 0, 4);
2494 } else if (n
== 5 &&
2495 (path
->flags
[0] & splashPathClosed
) &&
2496 !(path
->flags
[1] & splashPathLast
) &&
2497 !(path
->flags
[2] & splashPathLast
) &&
2498 !(path
->flags
[3] & splashPathLast
)) {
2499 path
->addStrokeAdjustHint(0, 2, 0, 4);
2500 path
->addStrokeAdjustHint(1, 3, 0, 4);
2504 if (thinLineMode
!= splashThinLineDefault
) {
2505 if (state
->clip
->getXMinI() == state
->clip
->getXMaxI()) {
2506 linePosI
= state
->clip
->getXMinI();
2508 } else if (state
->clip
->getXMinI() == state
->clip
->getXMaxI() - 1) {
2510 linePosI
= splashFloor(state
->clip
->getXMin() + state
->lineWidth
);
2511 } else if (state
->clip
->getYMinI() == state
->clip
->getYMaxI()) {
2512 linePosI
= state
->clip
->getYMinI();
2514 } else if (state
->clip
->getYMinI() == state
->clip
->getYMaxI() - 1) {
2516 linePosI
= splashFloor(state
->clip
->getYMin() + state
->lineWidth
);
2520 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
,
2521 adjustLine
, linePosI
);
2522 if (vectorAntialias
&& !inShading
) {
2526 yMinI
= state
->clip
->getYMinI();
2527 yMaxI
= state
->clip
->getYMaxI();
2528 if (vectorAntialias
&& !inShading
) {
2529 yMinI
= yMinI
* splashAASize
;
2530 yMaxI
= (yMaxI
+ 1) * splashAASize
- 1;
2532 scanner
= new SplashXPathScanner(xPath
, eo
, yMinI
, yMaxI
);
2534 // get the min and max x and y values
2535 if (vectorAntialias
&& !inShading
) {
2536 scanner
->getBBoxAA(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
2538 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
2541 if (eo
&& (yMinI
== yMaxI
|| xMinI
== xMaxI
) && thinLineMode
!= splashThinLineDefault
) {
2542 SplashCoord delta
, xMinFP
, yMinFP
, xMaxFP
, yMaxFP
;
2543 getBBoxFP(path
, &xMinFP
, &yMinFP
, &xMaxFP
, &yMaxFP
);
2544 delta
= (yMinI
== yMaxI
) ? yMaxFP
- yMinFP
: xMaxFP
- xMinFP
;
2546 opClipRes
= splashClipAllOutside
;
2554 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
))
2555 != splashClipAllOutside
) {
2556 if (scanner
->hasPartialClip()) {
2557 clipRes
= splashClipPartial
;
2560 pipeInit(&pipe
, 0, yMinI
, pattern
, NULL
, (Guchar
)splashRound(alpha
* 255),
2561 vectorAntialias
&& !inShading
, gFalse
);
2564 if (vectorAntialias
&& !inShading
) {
2565 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
2566 scanner
->renderAALine(aaBuf
, &x0
, &x1
, y
, thinLineMode
!= splashThinLineDefault
&& xMinI
== xMaxI
);
2567 if (clipRes
!= splashClipAllInside
) {
2568 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
, thinLineMode
!= splashThinLineDefault
&& xMinI
== xMaxI
);
2570 Guchar lineShape
= 255;
2571 GBool adjustLine
= gFalse
;
2572 if (thinLineMode
== splashThinLineShape
&& (xMinI
== xMaxI
|| yMinI
== yMaxI
)) {
2573 // compute line shape for thin lines:
2574 SplashCoord mx
, my
, delta
;
2575 transform(state
->matrix
, 0, 0, &mx
, &my
);
2576 transform(state
->matrix
, state
->lineWidth
, 0, &delta
, &my
);
2578 lineShape
= clip255((delta
- mx
) * 255);
2580 drawAALine(&pipe
, x0
, x1
, y
, adjustLine
, lineShape
);
2583 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
2584 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
2585 if (clipRes
== splashClipAllInside
) {
2586 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
2588 // limit the x range
2589 if (x0
< state
->clip
->getXMinI()) {
2590 x0
= state
->clip
->getXMinI();
2592 if (x1
> state
->clip
->getXMaxI()) {
2593 x1
= state
->clip
->getXMaxI();
2595 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
2596 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
2602 opClipRes
= clipRes
;
2609 GBool
Splash::pathAllOutside(SplashPath
*path
) {
2610 SplashCoord xMin1
, yMin1
, xMax1
, yMax1
;
2611 SplashCoord xMin2
, yMin2
, xMax2
, yMax2
;
2613 int xMinI
, yMinI
, xMaxI
, yMaxI
;
2616 xMin1
= xMax1
= path
->pts
[0].x
;
2617 yMin1
= yMax1
= path
->pts
[0].y
;
2618 for (i
= 1; i
< path
->length
; ++i
) {
2619 if (path
->pts
[i
].x
< xMin1
) {
2620 xMin1
= path
->pts
[i
].x
;
2621 } else if (path
->pts
[i
].x
> xMax1
) {
2622 xMax1
= path
->pts
[i
].x
;
2624 if (path
->pts
[i
].y
< yMin1
) {
2625 yMin1
= path
->pts
[i
].y
;
2626 } else if (path
->pts
[i
].y
> yMax1
) {
2627 yMax1
= path
->pts
[i
].y
;
2631 transform(state
->matrix
, xMin1
, yMin1
, &x
, &y
);
2634 transform(state
->matrix
, xMin1
, yMax1
, &x
, &y
);
2637 } else if (x
> xMax2
) {
2642 } else if (y
> yMax2
) {
2645 transform(state
->matrix
, xMax1
, yMin1
, &x
, &y
);
2648 } else if (x
> xMax2
) {
2653 } else if (y
> yMax2
) {
2656 transform(state
->matrix
, xMax1
, yMax1
, &x
, &y
);
2659 } else if (x
> xMax2
) {
2664 } else if (y
> yMax2
) {
2667 xMinI
= splashFloor(xMin2
);
2668 yMinI
= splashFloor(yMin2
);
2669 xMaxI
= splashFloor(xMax2
);
2670 yMaxI
= splashFloor(yMax2
);
2672 return state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
) ==
2673 splashClipAllOutside
;
2676 SplashError
Splash::xorFill(SplashPath
*path
, GBool eo
) {
2679 SplashXPathScanner
*scanner
;
2680 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
2681 SplashClipResult clipRes
, clipRes2
;
2682 SplashBlendFunc origBlendFunc
;
2684 if (path
->length
== 0) {
2685 return splashErrEmptyPath
;
2687 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
);
2689 scanner
= new SplashXPathScanner(xPath
, eo
, state
->clip
->getYMinI(),
2690 state
->clip
->getYMaxI());
2692 // get the min and max x and y values
2693 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
2696 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
))
2697 != splashClipAllOutside
) {
2698 if (scanner
->hasPartialClip()) {
2699 clipRes
= splashClipPartial
;
2702 origBlendFunc
= state
->blendFunc
;
2703 state
->blendFunc
= &blendXor
;
2704 pipeInit(&pipe
, 0, yMinI
, state
->fillPattern
, NULL
, 255, gFalse
, gFalse
);
2707 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
2708 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
2709 if (clipRes
== splashClipAllInside
) {
2710 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
2712 // limit the x range
2713 if (x0
< state
->clip
->getXMinI()) {
2714 x0
= state
->clip
->getXMinI();
2716 if (x1
> state
->clip
->getXMaxI()) {
2717 x1
= state
->clip
->getXMaxI();
2719 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
2720 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
2724 state
->blendFunc
= origBlendFunc
;
2726 opClipRes
= clipRes
;
2733 SplashError
Splash::fillChar(SplashCoord x
, SplashCoord y
,
2734 int c
, SplashFont
*font
) {
2735 SplashGlyphBitmap glyph
;
2737 int x0
, y0
, xFrac
, yFrac
;
2738 SplashClipResult clipRes
;
2741 printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
2742 (double)x
, (double)y
, c
, c
, c
);
2744 transform(state
->matrix
, x
, y
, &xt
, &yt
);
2745 x0
= splashFloor(xt
);
2746 xFrac
= splashFloor((xt
- x0
) * splashFontFraction
);
2747 y0
= splashFloor(yt
);
2748 yFrac
= splashFloor((yt
- y0
) * splashFontFraction
);
2749 if (!font
->getGlyph(c
, xFrac
, yFrac
, &glyph
, x0
, y0
, state
->clip
, &clipRes
)) {
2750 return splashErrNoGlyph
;
2752 if (clipRes
!= splashClipAllOutside
) {
2753 fillGlyph2(x0
, y0
, &glyph
, clipRes
== splashClipAllInside
);
2755 opClipRes
= clipRes
;
2756 if (glyph
.freeData
) {
2762 void Splash::fillGlyph(SplashCoord x
, SplashCoord y
,
2763 SplashGlyphBitmap
*glyph
) {
2767 transform(state
->matrix
, x
, y
, &xt
, &yt
);
2768 x0
= splashFloor(xt
);
2769 y0
= splashFloor(yt
);
2770 SplashClipResult clipRes
= state
->clip
->testRect(x0
- glyph
->x
,
2772 x0
- glyph
->x
+ glyph
->w
- 1,
2773 y0
- glyph
->y
+ glyph
->h
- 1);
2774 if (clipRes
!= splashClipAllOutside
) {
2775 fillGlyph2(x0
, y0
, glyph
, clipRes
== splashClipAllInside
);
2777 opClipRes
= clipRes
;
2780 void Splash::fillGlyph2(int x0
, int y0
, SplashGlyphBitmap
*glyph
, GBool noClip
) {
2785 int x1
, y1
, xx
, xx1
, yy
;
2788 int xStart
= x0
- glyph
->x
;
2789 int yStart
= y0
- glyph
->y
;
2790 int xxLimit
= glyph
->w
;
2791 int yyLimit
= glyph
->h
;
2796 p
+= (glyph
->aa
? glyph
->w
: splashCeil(glyph
->w
/ 8.0)) * -yStart
; // move p to the beginning of the first painted row
2807 xShift
= (-xStart
) % 8;
2813 if (xxLimit
+ xStart
>= bitmap
->width
) xxLimit
= bitmap
->width
- xStart
;
2814 if (yyLimit
+ yStart
>= bitmap
->height
) yyLimit
= bitmap
->height
- yStart
;
2818 pipeInit(&pipe
, xStart
, yStart
,
2819 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
2820 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2821 pipeSetXY(&pipe
, xStart
, y1
);
2822 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; ++xx
, ++x1
) {
2826 (this->*pipe
.run
)(&pipe
);
2836 const int widthEight
= splashCeil(glyph
->w
/ 8.0);
2838 pipeInit(&pipe
, xStart
, yStart
,
2839 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gFalse
, gFalse
);
2840 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2841 pipeSetXY(&pipe
, xStart
, y1
);
2842 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; xx
+= 8) {
2843 alpha0
= (xShift
> 0 ? (p
[xx
/ 8] << xShift
) | (p
[xx
/ 8 + 1] >> (8 - xShift
)) : p
[xx
/ 8]);
2844 for (xx1
= 0; xx1
< 8 && xx
+ xx1
< xxLimit
; ++xx1
, ++x1
) {
2845 if (alpha0
& 0x80) {
2846 (this->*pipe
.run
)(&pipe
);
2860 pipeInit(&pipe
, xStart
, yStart
,
2861 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
2862 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2863 pipeSetXY(&pipe
, xStart
, y1
);
2864 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; ++xx
, ++x1
) {
2865 if (state
->clip
->test(x1
, y1
)) {
2869 (this->*pipe
.run
)(&pipe
);
2882 const int widthEight
= splashCeil(glyph
->w
/ 8.0);
2884 pipeInit(&pipe
, xStart
, yStart
,
2885 state
->fillPattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), gFalse
, gFalse
);
2886 for (yy
= 0, y1
= yStart
; yy
< yyLimit
; ++yy
, ++y1
) {
2887 pipeSetXY(&pipe
, xStart
, y1
);
2888 for (xx
= 0, x1
= xStart
; xx
< xxLimit
; xx
+= 8) {
2889 alpha0
= (xShift
> 0 ? (p
[xx
/ 8] << xShift
) | (p
[xx
/ 8 + 1] >> (8 - xShift
)) : p
[xx
/ 8]);
2890 for (xx1
= 0; xx1
< 8 && xx
+ xx1
< xxLimit
; ++xx1
, ++x1
) {
2891 if (state
->clip
->test(x1
, y1
)) {
2892 if (alpha0
& 0x80) {
2893 (this->*pipe
.run
)(&pipe
);
2911 SplashError
Splash::fillImageMask(SplashImageMaskSource src
, void *srcData
,
2912 int w
, int h
, SplashCoord
*mat
,
2914 SplashBitmap
*scaledMask
;
2915 SplashClipResult clipRes
;
2916 GBool minorAxisZero
;
2917 int x0
, y0
, x1
, y1
, scaledWidth
, scaledHeight
;
2921 printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2922 w
, h
, (double)mat
[0], (double)mat
[1], (double)mat
[2],
2923 (double)mat
[3], (double)mat
[4], (double)mat
[5]);
2926 if (w
== 0 && h
== 0) return splashErrZeroImage
;
2928 // check for singular matrix
2929 if (!splashCheckDet(mat
[0], mat
[1], mat
[2], mat
[3], 0.000001)) {
2930 return splashErrSingularMatrix
;
2933 minorAxisZero
= mat
[1] == 0 && mat
[2] == 0;
2936 if (mat
[0] > 0 && minorAxisZero
&& mat
[3] > 0) {
2937 x0
= imgCoordMungeLowerC(mat
[4], glyphMode
);
2938 y0
= imgCoordMungeLowerC(mat
[5], glyphMode
);
2939 x1
= imgCoordMungeUpperC(mat
[0] + mat
[4], glyphMode
);
2940 y1
= imgCoordMungeUpperC(mat
[3] + mat
[5], glyphMode
);
2941 // make sure narrow images cover at least one pixel
2948 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
2949 opClipRes
= clipRes
;
2950 if (clipRes
!= splashClipAllOutside
) {
2951 scaledWidth
= x1
- x0
;
2952 scaledHeight
= y1
- y0
;
2953 yp
= h
/ scaledHeight
;
2954 if (yp
< 0 || yp
> INT_MAX
- 1) {
2955 return splashErrBadArg
;
2957 scaledMask
= scaleMask(src
, srcData
, w
, h
, scaledWidth
, scaledHeight
);
2958 blitMask(scaledMask
, x0
, y0
, clipRes
);
2962 // scaling plus vertical flip
2963 } else if (mat
[0] > 0 && minorAxisZero
&& mat
[3] < 0) {
2964 x0
= imgCoordMungeLowerC(mat
[4], glyphMode
);
2965 y0
= imgCoordMungeLowerC(mat
[3] + mat
[5], glyphMode
);
2966 x1
= imgCoordMungeUpperC(mat
[0] + mat
[4], glyphMode
);
2967 y1
= imgCoordMungeUpperC(mat
[5], glyphMode
);
2968 // make sure narrow images cover at least one pixel
2975 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
2976 opClipRes
= clipRes
;
2977 if (clipRes
!= splashClipAllOutside
) {
2978 scaledWidth
= x1
- x0
;
2979 scaledHeight
= y1
- y0
;
2980 yp
= h
/ scaledHeight
;
2981 if (yp
< 0 || yp
> INT_MAX
- 1) {
2982 return splashErrBadArg
;
2984 scaledMask
= scaleMask(src
, srcData
, w
, h
, scaledWidth
, scaledHeight
);
2985 vertFlipImage(scaledMask
, scaledWidth
, scaledHeight
, 1);
2986 blitMask(scaledMask
, x0
, y0
, clipRes
);
2992 arbitraryTransformMask(src
, srcData
, w
, h
, mat
, glyphMode
);
2998 void Splash::arbitraryTransformMask(SplashImageMaskSource src
, void *srcData
,
2999 int srcWidth
, int srcHeight
,
3000 SplashCoord
*mat
, GBool glyphMode
) {
3001 SplashBitmap
*scaledMask
;
3002 SplashClipResult clipRes
, clipRes2
;
3004 int scaledWidth
, scaledHeight
, t0
, t1
;
3005 SplashCoord r00
, r01
, r10
, r11
, det
, ir00
, ir01
, ir10
, ir11
;
3006 SplashCoord vx
[4], vy
[4];
3007 int xMin
, yMin
, xMax
, yMax
;
3008 ImageSection section
[3];
3010 int y
, xa
, xb
, x
, i
, xx
, yy
;
3012 // compute the four vertices of the target quadrilateral
3013 vx
[0] = mat
[4]; vy
[0] = mat
[5];
3014 vx
[1] = mat
[2] + mat
[4]; vy
[1] = mat
[3] + mat
[5];
3015 vx
[2] = mat
[0] + mat
[2] + mat
[4]; vy
[2] = mat
[1] + mat
[3] + mat
[5];
3016 vx
[3] = mat
[0] + mat
[4]; vy
[3] = mat
[1] + mat
[5];
3019 xMin
= imgCoordMungeLowerC(vx
[0], glyphMode
);
3020 xMax
= imgCoordMungeUpperC(vx
[0], glyphMode
);
3021 yMin
= imgCoordMungeLowerC(vy
[0], glyphMode
);
3022 yMax
= imgCoordMungeUpperC(vy
[0], glyphMode
);
3023 for (i
= 1; i
< 4; ++i
) {
3024 t0
= imgCoordMungeLowerC(vx
[i
], glyphMode
);
3028 t0
= imgCoordMungeUpperC(vx
[i
], glyphMode
);
3032 t1
= imgCoordMungeLowerC(vy
[i
], glyphMode
);
3036 t1
= imgCoordMungeUpperC(vy
[i
], glyphMode
);
3041 clipRes
= state
->clip
->testRect(xMin
, yMin
, xMax
- 1, yMax
- 1);
3042 opClipRes
= clipRes
;
3043 if (clipRes
== splashClipAllOutside
) {
3047 // compute the scale factors
3049 t0
= imgCoordMungeUpperC(mat
[0] + mat
[4], glyphMode
) -
3050 imgCoordMungeLowerC(mat
[4], glyphMode
);
3052 t0
= imgCoordMungeUpperC(mat
[4], glyphMode
) -
3053 imgCoordMungeLowerC(mat
[0] + mat
[4], glyphMode
);
3056 t1
= imgCoordMungeUpperC(mat
[1] + mat
[5], glyphMode
) -
3057 imgCoordMungeLowerC(mat
[5], glyphMode
);
3059 t1
= imgCoordMungeUpperC(mat
[5], glyphMode
) -
3060 imgCoordMungeLowerC(mat
[1] + mat
[5], glyphMode
);
3062 scaledWidth
= t0
> t1
? t0
: t1
;
3064 t0
= imgCoordMungeUpperC(mat
[2] + mat
[4], glyphMode
) -
3065 imgCoordMungeLowerC(mat
[4], glyphMode
);
3067 t0
= imgCoordMungeUpperC(mat
[4], glyphMode
) -
3068 imgCoordMungeLowerC(mat
[2] + mat
[4], glyphMode
);
3071 t1
= imgCoordMungeUpperC(mat
[3] + mat
[5], glyphMode
) -
3072 imgCoordMungeLowerC(mat
[5], glyphMode
);
3074 t1
= imgCoordMungeUpperC(mat
[5], glyphMode
) -
3075 imgCoordMungeLowerC(mat
[3] + mat
[5], glyphMode
);
3077 scaledHeight
= t0
> t1
? t0
: t1
;
3078 if (scaledWidth
== 0) {
3081 if (scaledHeight
== 0) {
3085 // compute the inverse transform (after scaling) matrix
3086 r00
= mat
[0] / scaledWidth
;
3087 r01
= mat
[1] / scaledWidth
;
3088 r10
= mat
[2] / scaledHeight
;
3089 r11
= mat
[3] / scaledHeight
;
3090 det
= r00
* r11
- r01
* r10
;
3091 if (splashAbs(det
) < 1e-6) {
3092 // this should be caught by the singular matrix check in fillImageMask
3100 // scale the input image
3101 scaledMask
= scaleMask(src
, srcData
, srcWidth
, srcHeight
,
3102 scaledWidth
, scaledHeight
);
3103 if (scaledMask
->data
== NULL
) {
3104 error(errInternal
, -1, "scaledMask->data is NULL in Splash::arbitraryTransformMask");
3109 // construct the three sections
3110 i
= (vy
[2] <= vy
[3]) ? 2 : 3;
3111 if (vy
[1] <= vy
[i
]) {
3114 if (vy
[0] < vy
[i
] || (i
!= 3 && vy
[0] == vy
[i
])) {
3117 if (vy
[i
] == vy
[(i
+1) & 3]) {
3118 section
[0].y0
= imgCoordMungeLowerC(vy
[i
], glyphMode
);
3119 section
[0].y1
= imgCoordMungeUpperC(vy
[(i
+2) & 3], glyphMode
) - 1;
3120 if (vx
[i
] < vx
[(i
+1) & 3]) {
3122 section
[0].ia1
= (i
+3) & 3;
3123 section
[0].ib0
= (i
+1) & 3;
3124 section
[0].ib1
= (i
+2) & 3;
3126 section
[0].ia0
= (i
+1) & 3;
3127 section
[0].ia1
= (i
+2) & 3;
3129 section
[0].ib1
= (i
+3) & 3;
3133 section
[0].y0
= imgCoordMungeLowerC(vy
[i
], glyphMode
);
3134 section
[2].y1
= imgCoordMungeUpperC(vy
[(i
+2) & 3], glyphMode
) - 1;
3135 section
[0].ia0
= section
[0].ib0
= i
;
3136 section
[2].ia1
= section
[2].ib1
= (i
+2) & 3;
3137 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3138 section
[0].ia1
= section
[2].ia0
= (i
+1) & 3;
3139 section
[0].ib1
= section
[2].ib0
= (i
+3) & 3;
3141 section
[0].ia1
= section
[2].ia0
= (i
+3) & 3;
3142 section
[0].ib1
= section
[2].ib0
= (i
+1) & 3;
3144 if (vy
[(i
+1) & 3] < vy
[(i
+3) & 3]) {
3145 section
[1].y0
= imgCoordMungeLowerC(vy
[(i
+1) & 3], glyphMode
);
3146 section
[2].y0
= imgCoordMungeUpperC(vy
[(i
+3) & 3], glyphMode
);
3147 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3148 section
[1].ia0
= (i
+1) & 3;
3149 section
[1].ia1
= (i
+2) & 3;
3151 section
[1].ib1
= (i
+3) & 3;
3154 section
[1].ia1
= (i
+3) & 3;
3155 section
[1].ib0
= (i
+1) & 3;
3156 section
[1].ib1
= (i
+2) & 3;
3159 section
[1].y0
= imgCoordMungeLowerC(vy
[(i
+3) & 3], glyphMode
);
3160 section
[2].y0
= imgCoordMungeUpperC(vy
[(i
+1) & 3], glyphMode
);
3161 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
3163 section
[1].ia1
= (i
+1) & 3;
3164 section
[1].ib0
= (i
+3) & 3;
3165 section
[1].ib1
= (i
+2) & 3;
3167 section
[1].ia0
= (i
+3) & 3;
3168 section
[1].ia1
= (i
+2) & 3;
3170 section
[1].ib1
= (i
+1) & 3;
3173 section
[0].y1
= section
[1].y0
- 1;
3174 section
[1].y1
= section
[2].y0
- 1;
3177 for (i
= 0; i
< nSections
; ++i
) {
3178 section
[i
].xa0
= vx
[section
[i
].ia0
];
3179 section
[i
].ya0
= vy
[section
[i
].ia0
];
3180 section
[i
].xa1
= vx
[section
[i
].ia1
];
3181 section
[i
].ya1
= vy
[section
[i
].ia1
];
3182 section
[i
].xb0
= vx
[section
[i
].ib0
];
3183 section
[i
].yb0
= vy
[section
[i
].ib0
];
3184 section
[i
].xb1
= vx
[section
[i
].ib1
];
3185 section
[i
].yb1
= vy
[section
[i
].ib1
];
3186 section
[i
].dxdya
= (section
[i
].xa1
- section
[i
].xa0
) /
3187 (section
[i
].ya1
- section
[i
].ya0
);
3188 section
[i
].dxdyb
= (section
[i
].xb1
- section
[i
].xb0
) /
3189 (section
[i
].yb1
- section
[i
].yb0
);
3192 // initialize the pixel pipe
3193 pipeInit(&pipe
, 0, 0, state
->fillPattern
, NULL
,
3194 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
3195 if (vectorAntialias
) {
3199 // make sure narrow images cover at least one pixel
3200 if (nSections
== 1) {
3201 if (section
[0].y0
== section
[0].y1
) {
3203 clipRes
= opClipRes
= splashClipPartial
;
3206 if (section
[0].y0
== section
[2].y1
) {
3208 clipRes
= opClipRes
= splashClipPartial
;
3212 // scan all pixels inside the target region
3213 for (i
= 0; i
< nSections
; ++i
) {
3214 for (y
= section
[i
].y0
; y
<= section
[i
].y1
; ++y
) {
3215 xa
= imgCoordMungeLowerC(section
[i
].xa0
+
3216 ((SplashCoord
)y
+ 0.5 - section
[i
].ya0
) *
3219 xb
= imgCoordMungeUpperC(section
[i
].xb0
+
3220 ((SplashCoord
)y
+ 0.5 - section
[i
].yb0
) *
3223 if (unlikely(xa
< 0))
3225 // make sure narrow images cover at least one pixel
3229 if (clipRes
!= splashClipAllInside
) {
3230 clipRes2
= state
->clip
->testSpan(xa
, xb
- 1, y
);
3234 for (x
= xa
; x
< xb
; ++x
) {
3235 // map (x+0.5, y+0.5) back to the scaled image
3236 xx
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir00
+
3237 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir10
);
3238 yy
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir01
+
3239 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir11
);
3240 // xx should always be within bounds, but floating point
3241 // inaccuracy can cause problems
3244 } else if (xx
>= scaledWidth
) {
3245 xx
= scaledWidth
- 1;
3249 } else if (yy
>= scaledHeight
) {
3250 yy
= scaledHeight
- 1;
3252 pipe
.shape
= scaledMask
->data
[yy
* scaledWidth
+ xx
];
3253 if (vectorAntialias
&& clipRes2
!= splashClipAllInside
) {
3254 drawAAPixel(&pipe
, x
, y
);
3256 drawPixel(&pipe
, x
, y
, clipRes2
== splashClipAllInside
);
3265 // Scale an image mask into a SplashBitmap.
3266 SplashBitmap
*Splash::scaleMask(SplashImageMaskSource src
, void *srcData
,
3267 int srcWidth
, int srcHeight
,
3268 int scaledWidth
, int scaledHeight
) {
3271 dest
= new SplashBitmap(scaledWidth
, scaledHeight
, 1, splashModeMono8
,
3273 if (scaledHeight
< srcHeight
) {
3274 if (scaledWidth
< srcWidth
) {
3275 scaleMaskYdXd(src
, srcData
, srcWidth
, srcHeight
,
3276 scaledWidth
, scaledHeight
, dest
);
3278 scaleMaskYdXu(src
, srcData
, srcWidth
, srcHeight
,
3279 scaledWidth
, scaledHeight
, dest
);
3282 if (scaledWidth
< srcWidth
) {
3283 scaleMaskYuXd(src
, srcData
, srcWidth
, srcHeight
,
3284 scaledWidth
, scaledHeight
, dest
);
3286 scaleMaskYuXu(src
, srcData
, srcWidth
, srcHeight
,
3287 scaledWidth
, scaledHeight
, dest
);
3293 void Splash::scaleMaskYdXd(SplashImageMaskSource src
, void *srcData
,
3294 int srcWidth
, int srcHeight
,
3295 int scaledWidth
, int scaledHeight
,
3296 SplashBitmap
*dest
) {
3301 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, d
, d0
, d1
;
3304 // Bresenham parameters for y scale
3305 yp
= srcHeight
/ scaledHeight
;
3306 yq
= srcHeight
% scaledHeight
;
3308 // Bresenham parameters for x scale
3309 xp
= srcWidth
/ scaledWidth
;
3310 xq
= srcWidth
% scaledWidth
;
3313 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3314 pixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
3316 // init y scale Bresenham
3319 destPtr
= dest
->data
;
3320 for (y
= 0; y
< scaledHeight
; ++y
) {
3322 // y scale Bresenham
3323 if ((yt
+= yq
) >= scaledHeight
) {
3330 // read rows from image
3331 memset(pixBuf
, 0, srcWidth
* sizeof(int));
3332 for (i
= 0; i
< yStep
; ++i
) {
3333 (*src
)(srcData
, lineBuf
);
3334 for (j
= 0; j
< srcWidth
; ++j
) {
3335 pixBuf
[j
] += lineBuf
[j
];
3339 // init x scale Bresenham
3341 d0
= (255 << 23) / (yStep
* xp
);
3342 d1
= (255 << 23) / (yStep
* (xp
+ 1));
3345 for (x
= 0; x
< scaledWidth
; ++x
) {
3347 // x scale Bresenham
3348 if ((xt
+= xq
) >= scaledWidth
) {
3357 // compute the final pixel
3359 for (i
= 0; i
< xStep
; ++i
) {
3360 pix
+= pixBuf
[xx
++];
3362 // (255 * pix) / xStep * yStep
3363 pix
= (pix
* d
) >> 23;
3366 *destPtr
++ = (Guchar
)pix
;
3374 void Splash::scaleMaskYdXu(SplashImageMaskSource src
, void *srcData
,
3375 int srcWidth
, int srcHeight
,
3376 int scaledWidth
, int scaledHeight
,
3377 SplashBitmap
*dest
) {
3382 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, d
;
3385 destPtr
= dest
->data
;
3386 if (destPtr
== NULL
) {
3387 error(errInternal
, -1, "dest->data is NULL in Splash::scaleMaskYdXu");
3391 // Bresenham parameters for y scale
3392 yp
= srcHeight
/ scaledHeight
;
3393 yq
= srcHeight
% scaledHeight
;
3395 // Bresenham parameters for x scale
3396 xp
= scaledWidth
/ srcWidth
;
3397 xq
= scaledWidth
% srcWidth
;
3400 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3401 pixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
3403 // init y scale Bresenham
3406 for (y
= 0; y
< scaledHeight
; ++y
) {
3408 // y scale Bresenham
3409 if ((yt
+= yq
) >= scaledHeight
) {
3416 // read rows from image
3417 memset(pixBuf
, 0, srcWidth
* sizeof(int));
3418 for (i
= 0; i
< yStep
; ++i
) {
3419 (*src
)(srcData
, lineBuf
);
3420 for (j
= 0; j
< srcWidth
; ++j
) {
3421 pixBuf
[j
] += lineBuf
[j
];
3425 // init x scale Bresenham
3427 d
= (255 << 23) / yStep
;
3429 for (x
= 0; x
< srcWidth
; ++x
) {
3431 // x scale Bresenham
3432 if ((xt
+= xq
) >= srcWidth
) {
3439 // compute the final pixel
3441 // (255 * pix) / yStep
3442 pix
= (pix
* d
) >> 23;
3445 for (i
= 0; i
< xStep
; ++i
) {
3446 *destPtr
++ = (Guchar
)pix
;
3455 void Splash::scaleMaskYuXd(SplashImageMaskSource src
, void *srcData
,
3456 int srcWidth
, int srcHeight
,
3457 int scaledWidth
, int scaledHeight
,
3458 SplashBitmap
*dest
) {
3461 Guchar
*destPtr0
, *destPtr
;
3462 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, d
, d0
, d1
;
3465 destPtr0
= dest
->data
;
3466 if (destPtr0
== NULL
) {
3467 error(errInternal
, -1, "dest->data is NULL in Splash::scaleMaskYuXd");
3471 // Bresenham parameters for y scale
3472 yp
= scaledHeight
/ srcHeight
;
3473 yq
= scaledHeight
% srcHeight
;
3475 // Bresenham parameters for x scale
3476 xp
= srcWidth
/ scaledWidth
;
3477 xq
= srcWidth
% scaledWidth
;
3480 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3482 // init y scale Bresenham
3485 for (y
= 0; y
< srcHeight
; ++y
) {
3487 // y scale Bresenham
3488 if ((yt
+= yq
) >= srcHeight
) {
3495 // read row from image
3496 (*src
)(srcData
, lineBuf
);
3498 // init x scale Bresenham
3500 d0
= (255 << 23) / xp
;
3501 d1
= (255 << 23) / (xp
+ 1);
3504 for (x
= 0; x
< scaledWidth
; ++x
) {
3506 // x scale Bresenham
3507 if ((xt
+= xq
) >= scaledWidth
) {
3516 // compute the final pixel
3518 for (i
= 0; i
< xStep
; ++i
) {
3519 pix
+= lineBuf
[xx
++];
3521 // (255 * pix) / xStep
3522 pix
= (pix
* d
) >> 23;
3525 for (i
= 0; i
< yStep
; ++i
) {
3526 destPtr
= destPtr0
+ i
* scaledWidth
+ x
;
3527 *destPtr
= (Guchar
)pix
;
3531 destPtr0
+= yStep
* scaledWidth
;
3537 void Splash::scaleMaskYuXu(SplashImageMaskSource src
, void *srcData
,
3538 int srcWidth
, int srcHeight
,
3539 int scaledWidth
, int scaledHeight
,
3540 SplashBitmap
*dest
) {
3543 Guchar
*destPtr0
, *destPtr
;
3544 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
;
3547 destPtr0
= dest
->data
;
3548 if (destPtr0
== NULL
) {
3549 error(errInternal
, -1, "dest->data is NULL in Splash::scaleMaskYuXu");
3553 // Bresenham parameters for y scale
3554 yp
= scaledHeight
/ srcHeight
;
3555 yq
= scaledHeight
% srcHeight
;
3557 // Bresenham parameters for x scale
3558 xp
= scaledWidth
/ srcWidth
;
3559 xq
= scaledWidth
% srcWidth
;
3562 lineBuf
= (Guchar
*)gmalloc(srcWidth
);
3564 // init y scale Bresenham
3567 for (y
= 0; y
< srcHeight
; ++y
) {
3569 // y scale Bresenham
3570 if ((yt
+= yq
) >= srcHeight
) {
3577 // read row from image
3578 (*src
)(srcData
, lineBuf
);
3580 // init x scale Bresenham
3584 for (x
= 0; x
< srcWidth
; ++x
) {
3586 // x scale Bresenham
3587 if ((xt
+= xq
) >= srcWidth
) {
3594 // compute the final pixel
3595 pix
= lineBuf
[x
] ? 255 : 0;
3598 for (i
= 0; i
< yStep
; ++i
) {
3599 for (j
= 0; j
< xStep
; ++j
) {
3600 destPtr
= destPtr0
+ i
* scaledWidth
+ xx
+ j
;
3601 *destPtr
++ = (Guchar
)pix
;
3608 destPtr0
+= yStep
* scaledWidth
;
3614 void Splash::blitMask(SplashBitmap
*src
, int xDest
, int yDest
,
3615 SplashClipResult clipRes
) {
3620 w
= src
->getWidth();
3621 h
= src
->getHeight();
3622 p
= src
->getDataPtr();
3624 error(errInternal
, -1, "src->getDataPtr() is NULL in Splash::blitMask");
3627 if (vectorAntialias
&& clipRes
!= splashClipAllInside
) {
3628 pipeInit(&pipe
, xDest
, yDest
, state
->fillPattern
, NULL
,
3629 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
3631 for (y
= 0; y
< h
; ++y
) {
3632 for (x
= 0; x
< w
; ++x
) {
3634 drawAAPixel(&pipe
, xDest
+ x
, yDest
+ y
);
3638 pipeInit(&pipe
, xDest
, yDest
, state
->fillPattern
, NULL
,
3639 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
3640 if (clipRes
== splashClipAllInside
) {
3641 for (y
= 0; y
< h
; ++y
) {
3642 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
3643 for (x
= 0; x
< w
; ++x
) {
3646 (this->*pipe
.run
)(&pipe
);
3654 updateModX(xDest
+ w
- 1);
3656 updateModY(yDest
+ h
- 1);
3658 for (y
= 0; y
< h
; ++y
) {
3659 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
3660 for (x
= 0; x
< w
; ++x
) {
3661 if (*p
&& state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
3663 (this->*pipe
.run
)(&pipe
);
3664 updateModX(xDest
+ x
);
3665 updateModY(yDest
+ y
);
3676 SplashError
Splash::drawImage(SplashImageSource src
, SplashICCTransform tf
, void *srcData
,
3677 SplashColorMode srcMode
, GBool srcAlpha
,
3678 int w
, int h
, SplashCoord
*mat
, GBool interpolate
,
3679 GBool tilingPattern
) {
3681 SplashBitmap
*scaledImg
;
3682 SplashClipResult clipRes
;
3683 GBool minorAxisZero
;
3684 int x0
, y0
, x1
, y1
, scaledWidth
, scaledHeight
;
3689 printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
3690 srcMode
, srcAlpha
, w
, h
, (double)mat
[0], (double)mat
[1], (double)mat
[2],
3691 (double)mat
[3], (double)mat
[4], (double)mat
[5]);
3694 // check color modes
3695 ok
= gFalse
; // make gcc happy
3696 nComps
= 0; // make gcc happy
3697 switch (bitmap
->mode
) {
3698 case splashModeMono1
:
3699 case splashModeMono8
:
3700 ok
= srcMode
== splashModeMono8
;
3703 case splashModeRGB8
:
3704 ok
= srcMode
== splashModeRGB8
;
3707 case splashModeXBGR8
:
3708 ok
= srcMode
== splashModeXBGR8
;
3711 case splashModeBGR8
:
3712 ok
= srcMode
== splashModeBGR8
;
3716 case splashModeCMYK8
:
3717 ok
= srcMode
== splashModeCMYK8
;
3720 case splashModeDeviceN8
:
3721 ok
= srcMode
== splashModeDeviceN8
;
3722 nComps
= SPOT_NCOMPS
+4;
3730 return splashErrModeMismatch
;
3733 // check for singular matrix
3734 if (!splashCheckDet(mat
[0], mat
[1], mat
[2], mat
[3], 0.000001)) {
3735 return splashErrSingularMatrix
;
3738 minorAxisZero
= mat
[1] == 0 && mat
[2] == 0;
3741 if (mat
[0] > 0 && minorAxisZero
&& mat
[3] > 0) {
3742 x0
= imgCoordMungeLower(mat
[4]);
3743 y0
= imgCoordMungeLower(mat
[5]);
3744 x1
= imgCoordMungeUpper(mat
[0] + mat
[4]);
3745 y1
= imgCoordMungeUpper(mat
[3] + mat
[5]);
3746 // make sure narrow images cover at least one pixel
3753 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
3754 opClipRes
= clipRes
;
3755 if (clipRes
!= splashClipAllOutside
) {
3756 scaledWidth
= x1
- x0
;
3757 scaledHeight
= y1
- y0
;
3758 yp
= h
/ scaledHeight
;
3759 if (yp
< 0 || yp
> INT_MAX
- 1) {
3760 return splashErrBadArg
;
3762 scaledImg
= scaleImage(src
, srcData
, srcMode
, nComps
, srcAlpha
, w
, h
,
3763 scaledWidth
, scaledHeight
, interpolate
, tilingPattern
);
3764 if (scaledImg
== NULL
) {
3765 return splashErrBadArg
;
3768 (*tf
)(srcData
, scaledImg
);
3770 blitImage(scaledImg
, srcAlpha
, x0
, y0
, clipRes
);
3774 // scaling plus vertical flip
3775 } else if (mat
[0] > 0 && minorAxisZero
&& mat
[3] < 0) {
3776 x0
= imgCoordMungeLower(mat
[4]);
3777 y0
= imgCoordMungeLower(mat
[3] + mat
[5]);
3778 x1
= imgCoordMungeUpper(mat
[0] + mat
[4]);
3779 y1
= imgCoordMungeUpper(mat
[5]);
3781 if (mat
[4] + mat
[0] * 0.5 < x0
) {
3788 if (mat
[5] + mat
[1] * 0.5 < y0
) {
3794 clipRes
= state
->clip
->testRect(x0
, y0
, x1
- 1, y1
- 1);
3795 opClipRes
= clipRes
;
3796 if (clipRes
!= splashClipAllOutside
) {
3797 scaledWidth
= x1
- x0
;
3798 scaledHeight
= y1
- y0
;
3799 yp
= h
/ scaledHeight
;
3800 if (yp
< 0 || yp
> INT_MAX
- 1) {
3801 return splashErrBadArg
;
3803 scaledImg
= scaleImage(src
, srcData
, srcMode
, nComps
, srcAlpha
, w
, h
,
3804 scaledWidth
, scaledHeight
, interpolate
, tilingPattern
);
3805 if (scaledImg
== NULL
) {
3806 return splashErrBadArg
;
3809 (*tf
)(srcData
, scaledImg
);
3811 vertFlipImage(scaledImg
, scaledWidth
, scaledHeight
, nComps
);
3812 blitImage(scaledImg
, srcAlpha
, x0
, y0
, clipRes
);
3818 return arbitraryTransformImage(src
, tf
, srcData
, srcMode
, nComps
, srcAlpha
,
3819 w
, h
, mat
, interpolate
, tilingPattern
);
3825 SplashError
Splash::arbitraryTransformImage(SplashImageSource src
, SplashICCTransform tf
, void *srcData
,
3826 SplashColorMode srcMode
, int nComps
,
3828 int srcWidth
, int srcHeight
,
3829 SplashCoord
*mat
, GBool interpolate
,
3830 GBool tilingPattern
) {
3831 SplashBitmap
*scaledImg
;
3832 SplashClipResult clipRes
, clipRes2
;
3835 int scaledWidth
, scaledHeight
, t0
, t1
, th
;
3836 SplashCoord r00
, r01
, r10
, r11
, det
, ir00
, ir01
, ir10
, ir11
;
3837 SplashCoord vx
[4], vy
[4];
3838 int xMin
, yMin
, xMax
, yMax
;
3839 ImageSection section
[3];
3841 int y
, xa
, xb
, x
, i
, xx
, yy
, yp
;
3843 // compute the four vertices of the target quadrilateral
3844 vx
[0] = mat
[4]; vy
[0] = mat
[5];
3845 vx
[1] = mat
[2] + mat
[4]; vy
[1] = mat
[3] + mat
[5];
3846 vx
[2] = mat
[0] + mat
[2] + mat
[4]; vy
[2] = mat
[1] + mat
[3] + mat
[5];
3847 vx
[3] = mat
[0] + mat
[4]; vy
[3] = mat
[1] + mat
[5];
3850 xMin
= imgCoordMungeLower(vx
[0]);
3851 xMax
= imgCoordMungeUpper(vx
[0]);
3852 yMin
= imgCoordMungeLower(vy
[0]);
3853 yMax
= imgCoordMungeUpper(vy
[0]);
3854 for (i
= 1; i
< 4; ++i
) {
3855 t0
= imgCoordMungeLower(vx
[i
]);
3859 t0
= imgCoordMungeUpper(vx
[i
]);
3863 t1
= imgCoordMungeLower(vy
[i
]);
3867 t1
= imgCoordMungeUpper(vy
[i
]);
3872 clipRes
= state
->clip
->testRect(xMin
, yMin
, xMax
, yMax
);
3873 opClipRes
= clipRes
;
3874 if (clipRes
== splashClipAllOutside
) {
3878 // compute the scale factors
3879 if (splashAbs(mat
[0]) >= splashAbs(mat
[1])) {
3880 scaledWidth
= xMax
- xMin
;
3881 scaledHeight
= yMax
- yMin
;
3883 scaledWidth
= yMax
- yMin
;
3884 scaledHeight
= xMax
- xMin
;
3886 if (scaledHeight
<= 1 || scaledWidth
<= 1 || tilingPattern
) {
3888 t0
= imgCoordMungeUpper(mat
[0] + mat
[4]) - imgCoordMungeLower(mat
[4]);
3890 t0
= imgCoordMungeUpper(mat
[4]) - imgCoordMungeLower(mat
[0] + mat
[4]);
3893 t1
= imgCoordMungeUpper(mat
[1] + mat
[5]) - imgCoordMungeLower(mat
[5]);
3895 t1
= imgCoordMungeUpper(mat
[5]) - imgCoordMungeLower(mat
[1] + mat
[5]);
3897 scaledWidth
= t0
> t1
? t0
: t1
;
3899 t0
= imgCoordMungeUpper(mat
[2] + mat
[4]) - imgCoordMungeLower(mat
[4]);
3900 if (splashAbs(mat
[1]) >= 1) {
3901 th
= imgCoordMungeUpper(mat
[2]) - imgCoordMungeLower(mat
[0] * mat
[3] / mat
[1]);
3902 if (th
> t0
) t0
= th
;
3905 t0
= imgCoordMungeUpper(mat
[4]) - imgCoordMungeLower(mat
[2] + mat
[4]);
3906 if (splashAbs(mat
[1]) >= 1) {
3907 th
= imgCoordMungeUpper(mat
[0] * mat
[3] / mat
[1]) - imgCoordMungeLower(mat
[2]);
3908 if (th
> t0
) t0
= th
;
3912 t1
= imgCoordMungeUpper(mat
[3] + mat
[5]) - imgCoordMungeLower(mat
[5]);
3913 if (splashAbs(mat
[0]) >= 1) {
3914 th
= imgCoordMungeUpper(mat
[3]) - imgCoordMungeLower(mat
[1] * mat
[2] / mat
[0]);
3915 if (th
> t1
) t1
= th
;
3918 t1
= imgCoordMungeUpper(mat
[5]) - imgCoordMungeLower(mat
[3] + mat
[5]);
3919 if (splashAbs(mat
[0]) >= 1) {
3920 th
= imgCoordMungeUpper(mat
[1] * mat
[2] / mat
[0]) - imgCoordMungeLower(mat
[3]);
3921 if (th
> t1
) t1
= th
;
3924 scaledHeight
= t0
> t1
? t0
: t1
;
3926 if (scaledWidth
== 0) {
3929 if (scaledHeight
== 0) {
3933 // compute the inverse transform (after scaling) matrix
3934 r00
= mat
[0] / scaledWidth
;
3935 r01
= mat
[1] / scaledWidth
;
3936 r10
= mat
[2] / scaledHeight
;
3937 r11
= mat
[3] / scaledHeight
;
3938 det
= r00
* r11
- r01
* r10
;
3939 if (splashAbs(det
) < 1e-6) {
3940 // this should be caught by the singular matrix check in drawImage
3941 return splashErrBadArg
;
3948 // scale the input image
3949 yp
= srcHeight
/ scaledHeight
;
3950 if (yp
< 0 || yp
> INT_MAX
- 1) {
3951 return splashErrBadArg
;
3953 scaledImg
= scaleImage(src
, srcData
, srcMode
, nComps
, srcAlpha
,
3954 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, interpolate
);
3956 if (scaledImg
== NULL
) {
3957 return splashErrBadArg
;
3961 (*tf
)(srcData
, scaledImg
);
3963 // construct the three sections
3965 if (vy
[1] < vy
[i
]) {
3968 if (vy
[2] < vy
[i
]) {
3971 if (vy
[3] < vy
[i
]) {
3974 // NB: if using fixed point, 0.000001 will be truncated to zero,
3975 // so these two comparisons must be <=, not <
3976 if (splashAbs(vy
[i
] - vy
[(i
-1) & 3]) <= 0.000001 &&
3977 vy
[(i
-1) & 3] < vy
[(i
+1) & 3]) {
3980 if (splashAbs(vy
[i
] - vy
[(i
+1) & 3]) <= 0.000001) {
3981 section
[0].y0
= imgCoordMungeLower(vy
[i
]);
3982 section
[0].y1
= imgCoordMungeUpper(vy
[(i
+2) & 3]) - 1;
3983 if (vx
[i
] < vx
[(i
+1) & 3]) {
3985 section
[0].ia1
= (i
+3) & 3;
3986 section
[0].ib0
= (i
+1) & 3;
3987 section
[0].ib1
= (i
+2) & 3;
3989 section
[0].ia0
= (i
+1) & 3;
3990 section
[0].ia1
= (i
+2) & 3;
3992 section
[0].ib1
= (i
+3) & 3;
3996 section
[0].y0
= imgCoordMungeLower(vy
[i
]);
3997 section
[2].y1
= imgCoordMungeUpper(vy
[(i
+2) & 3]) - 1;
3998 section
[0].ia0
= section
[0].ib0
= i
;
3999 section
[2].ia1
= section
[2].ib1
= (i
+2) & 3;
4000 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
4001 section
[0].ia1
= section
[2].ia0
= (i
+1) & 3;
4002 section
[0].ib1
= section
[2].ib0
= (i
+3) & 3;
4004 section
[0].ia1
= section
[2].ia0
= (i
+3) & 3;
4005 section
[0].ib1
= section
[2].ib0
= (i
+1) & 3;
4007 if (vy
[(i
+1) & 3] < vy
[(i
+3) & 3]) {
4008 section
[1].y0
= imgCoordMungeLower(vy
[(i
+1) & 3]);
4009 section
[2].y0
= imgCoordMungeUpper(vy
[(i
+3) & 3]);
4010 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
4011 section
[1].ia0
= (i
+1) & 3;
4012 section
[1].ia1
= (i
+2) & 3;
4014 section
[1].ib1
= (i
+3) & 3;
4017 section
[1].ia1
= (i
+3) & 3;
4018 section
[1].ib0
= (i
+1) & 3;
4019 section
[1].ib1
= (i
+2) & 3;
4022 section
[1].y0
= imgCoordMungeLower(vy
[(i
+3) & 3]);
4023 section
[2].y0
= imgCoordMungeUpper(vy
[(i
+1) & 3]);
4024 if (vx
[(i
+1) & 3] < vx
[(i
+3) & 3]) {
4026 section
[1].ia1
= (i
+1) & 3;
4027 section
[1].ib0
= (i
+3) & 3;
4028 section
[1].ib1
= (i
+2) & 3;
4030 section
[1].ia0
= (i
+3) & 3;
4031 section
[1].ia1
= (i
+2) & 3;
4033 section
[1].ib1
= (i
+1) & 3;
4036 section
[0].y1
= section
[1].y0
- 1;
4037 section
[1].y1
= section
[2].y0
- 1;
4040 for (i
= 0; i
< nSections
; ++i
) {
4041 section
[i
].xa0
= vx
[section
[i
].ia0
];
4042 section
[i
].ya0
= vy
[section
[i
].ia0
];
4043 section
[i
].xa1
= vx
[section
[i
].ia1
];
4044 section
[i
].ya1
= vy
[section
[i
].ia1
];
4045 section
[i
].xb0
= vx
[section
[i
].ib0
];
4046 section
[i
].yb0
= vy
[section
[i
].ib0
];
4047 section
[i
].xb1
= vx
[section
[i
].ib1
];
4048 section
[i
].yb1
= vy
[section
[i
].ib1
];
4049 section
[i
].dxdya
= (section
[i
].xa1
- section
[i
].xa0
) /
4050 (section
[i
].ya1
- section
[i
].ya0
);
4051 section
[i
].dxdyb
= (section
[i
].xb1
- section
[i
].xb0
) /
4052 (section
[i
].yb1
- section
[i
].yb0
);
4055 // initialize the pixel pipe
4056 pipeInit(&pipe
, 0, 0, NULL
, pixel
,
4057 (Guchar
)splashRound(state
->fillAlpha
* 255),
4058 srcAlpha
|| (vectorAntialias
&& clipRes
!= splashClipAllInside
),
4060 if (vectorAntialias
) {
4064 // make sure narrow images cover at least one pixel
4065 if (nSections
== 1) {
4066 if (section
[0].y0
== section
[0].y1
) {
4068 clipRes
= opClipRes
= splashClipPartial
;
4071 if (section
[0].y0
== section
[2].y1
) {
4073 clipRes
= opClipRes
= splashClipPartial
;
4077 // scan all pixels inside the target region
4078 for (i
= 0; i
< nSections
; ++i
) {
4079 for (y
= section
[i
].y0
; y
<= section
[i
].y1
; ++y
) {
4080 xa
= imgCoordMungeLower(section
[i
].xa0
+
4081 ((SplashCoord
)y
+ 0.5 - section
[i
].ya0
) *
4083 if (unlikely(xa
< 0))
4085 xb
= imgCoordMungeUpper(section
[i
].xb0
+
4086 ((SplashCoord
)y
+ 0.5 - section
[i
].yb0
) *
4088 // make sure narrow images cover at least one pixel
4092 if (clipRes
!= splashClipAllInside
) {
4093 clipRes2
= state
->clip
->testSpan(xa
, xb
- 1, y
);
4097 for (x
= xa
; x
< xb
; ++x
) {
4098 // map (x+0.5, y+0.5) back to the scaled image
4099 xx
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir00
+
4100 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir10
);
4101 yy
= splashFloor(((SplashCoord
)x
+ 0.5 - mat
[4]) * ir01
+
4102 ((SplashCoord
)y
+ 0.5 - mat
[5]) * ir11
);
4103 // xx should always be within bounds, but floating point
4104 // inaccuracy can cause problems
4107 } else if (xx
>= scaledWidth
) {
4108 xx
= scaledWidth
- 1;
4112 } else if (yy
>= scaledHeight
) {
4113 yy
= scaledHeight
- 1;
4115 scaledImg
->getPixel(xx
, yy
, pixel
);
4117 pipe
.shape
= scaledImg
->alpha
[yy
* scaledWidth
+ xx
];
4121 if (vectorAntialias
&& clipRes2
!= splashClipAllInside
) {
4122 drawAAPixel(&pipe
, x
, y
);
4124 drawPixel(&pipe
, x
, y
, clipRes2
== splashClipAllInside
);
4134 // determine if a scaled image requires interpolation based on the scale and
4135 // the interpolate flag from the image dictionary
4136 static GBool
isImageInterpolationRequired(int srcWidth
, int srcHeight
,
4137 int scaledWidth
, int scaledHeight
,
4138 GBool interpolate
) {
4142 /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
4143 if (scaledWidth
/ srcWidth
>= 4 || scaledHeight
/ srcHeight
>= 4)
4149 // Scale an image into a SplashBitmap.
4150 SplashBitmap
*Splash::scaleImage(SplashImageSource src
, void *srcData
,
4151 SplashColorMode srcMode
, int nComps
,
4152 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4153 int scaledWidth
, int scaledHeight
, GBool interpolate
, GBool tilingPattern
) {
4156 dest
= new SplashBitmap(scaledWidth
, scaledHeight
, 1, srcMode
, srcAlpha
, gTrue
, bitmap
->getSeparationList());
4157 if (dest
->getDataPtr() != NULL
) {
4158 if (scaledHeight
< srcHeight
) {
4159 if (scaledWidth
< srcWidth
) {
4160 scaleImageYdXd(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4161 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4163 scaleImageYdXu(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4164 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4167 if (scaledWidth
< srcWidth
) {
4168 scaleImageYuXd(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4169 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4171 if (!tilingPattern
&& isImageInterpolationRequired(srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, interpolate
)) {
4172 scaleImageYuXuBilinear(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4173 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4175 scaleImageYuXu(src
, srcData
, srcMode
, nComps
, srcAlpha
,
4176 srcWidth
, srcHeight
, scaledWidth
, scaledHeight
, dest
);
4187 void Splash::scaleImageYdXd(SplashImageSource src
, void *srcData
,
4188 SplashColorMode srcMode
, int nComps
,
4189 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4190 int scaledWidth
, int scaledHeight
,
4191 SplashBitmap
*dest
) {
4192 Guchar
*lineBuf
, *alphaLineBuf
;
4193 Guint
*pixBuf
, *alphaPixBuf
;
4194 Guint pix0
, pix1
, pix2
;
4197 Guint pix
[SPOT_NCOMPS
+4], cp
;
4200 Guchar
*destPtr
, *destAlphaPtr
;
4201 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, xxa
, d
, d0
, d1
;
4204 // Bresenham parameters for y scale
4205 yp
= srcHeight
/ scaledHeight
;
4206 yq
= srcHeight
% scaledHeight
;
4208 // Bresenham parameters for x scale
4209 xp
= srcWidth
/ scaledWidth
;
4210 xq
= srcWidth
% scaledWidth
;
4213 lineBuf
= (Guchar
*)gmallocn(srcWidth
, nComps
);
4214 pixBuf
= (Guint
*)gmallocn(srcWidth
, nComps
* sizeof(int));
4216 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4217 alphaPixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
4219 alphaLineBuf
= NULL
;
4223 // init y scale Bresenham
4226 destPtr
= dest
->data
;
4227 destAlphaPtr
= dest
->alpha
;
4228 for (y
= 0; y
< scaledHeight
; ++y
) {
4230 // y scale Bresenham
4231 if ((yt
+= yq
) >= scaledHeight
) {
4238 // read rows from image
4239 memset(pixBuf
, 0, srcWidth
* nComps
* sizeof(int));
4241 memset(alphaPixBuf
, 0, srcWidth
* sizeof(int));
4243 for (i
= 0; i
< yStep
; ++i
) {
4244 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4245 for (j
= 0; j
< srcWidth
* nComps
; ++j
) {
4246 pixBuf
[j
] += lineBuf
[j
];
4249 for (j
= 0; j
< srcWidth
; ++j
) {
4250 alphaPixBuf
[j
] += alphaLineBuf
[j
];
4255 // init x scale Bresenham
4257 d0
= (1 << 23) / (yStep
* xp
);
4258 d1
= (1 << 23) / (yStep
* (xp
+ 1));
4261 for (x
= 0; x
< scaledWidth
; ++x
) {
4263 // x scale Bresenham
4264 if ((xt
+= xq
) >= scaledWidth
) {
4275 case splashModeMono8
:
4277 // compute the final pixel
4279 for (i
= 0; i
< xStep
; ++i
) {
4280 pix0
+= pixBuf
[xx
++];
4282 // pix / xStep * yStep
4283 pix0
= (pix0
* d
) >> 23;
4286 *destPtr
++ = (Guchar
)pix0
;
4289 case splashModeRGB8
:
4291 // compute the final pixel
4292 pix0
= pix1
= pix2
= 0;
4293 for (i
= 0; i
< xStep
; ++i
) {
4295 pix1
+= pixBuf
[xx
+1];
4296 pix2
+= pixBuf
[xx
+2];
4299 // pix / xStep * yStep
4300 pix0
= (pix0
* d
) >> 23;
4301 pix1
= (pix1
* d
) >> 23;
4302 pix2
= (pix2
* d
) >> 23;
4305 *destPtr
++ = (Guchar
)pix0
;
4306 *destPtr
++ = (Guchar
)pix1
;
4307 *destPtr
++ = (Guchar
)pix2
;
4310 case splashModeXBGR8
:
4312 // compute the final pixel
4313 pix0
= pix1
= pix2
= 0;
4314 for (i
= 0; i
< xStep
; ++i
) {
4316 pix1
+= pixBuf
[xx
+1];
4317 pix2
+= pixBuf
[xx
+2];
4320 // pix / xStep * yStep
4321 pix0
= (pix0
* d
) >> 23;
4322 pix1
= (pix1
* d
) >> 23;
4323 pix2
= (pix2
* d
) >> 23;
4326 *destPtr
++ = (Guchar
)pix2
;
4327 *destPtr
++ = (Guchar
)pix1
;
4328 *destPtr
++ = (Guchar
)pix0
;
4329 *destPtr
++ = (Guchar
)255;
4332 case splashModeBGR8
:
4334 // compute the final pixel
4335 pix0
= pix1
= pix2
= 0;
4336 for (i
= 0; i
< xStep
; ++i
) {
4338 pix1
+= pixBuf
[xx
+1];
4339 pix2
+= pixBuf
[xx
+2];
4342 // pix / xStep * yStep
4343 pix0
= (pix0
* d
) >> 23;
4344 pix1
= (pix1
* d
) >> 23;
4345 pix2
= (pix2
* d
) >> 23;
4348 *destPtr
++ = (Guchar
)pix2
;
4349 *destPtr
++ = (Guchar
)pix1
;
4350 *destPtr
++ = (Guchar
)pix0
;
4354 case splashModeCMYK8
:
4356 // compute the final pixel
4357 pix0
= pix1
= pix2
= pix3
= 0;
4358 for (i
= 0; i
< xStep
; ++i
) {
4360 pix1
+= pixBuf
[xx
+1];
4361 pix2
+= pixBuf
[xx
+2];
4362 pix3
+= pixBuf
[xx
+3];
4365 // pix / xStep * yStep
4366 pix0
= (pix0
* d
) >> 23;
4367 pix1
= (pix1
* d
) >> 23;
4368 pix2
= (pix2
* d
) >> 23;
4369 pix3
= (pix3
* d
) >> 23;
4372 *destPtr
++ = (Guchar
)pix0
;
4373 *destPtr
++ = (Guchar
)pix1
;
4374 *destPtr
++ = (Guchar
)pix2
;
4375 *destPtr
++ = (Guchar
)pix3
;
4377 case splashModeDeviceN8
:
4379 // compute the final pixel
4380 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4382 for (i
= 0; i
< xStep
; ++i
) {
4383 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++) {
4384 pix
[cp
] += pixBuf
[xx
+ cp
];
4386 xx
+= (SPOT_NCOMPS
+4);
4388 // pix / xStep * yStep
4389 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4390 pix
[cp
] = (pix
[cp
] * d
) >> 23;
4393 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4394 *destPtr
++ = (Guchar
)pix
[cp
];
4399 case splashModeMono1
: // mono1 is not allowed
4407 for (i
= 0; i
< xStep
; ++i
, ++xxa
) {
4408 alpha
+= alphaPixBuf
[xxa
];
4410 // alpha / xStep * yStep
4411 alpha
= (alpha
* d
) >> 23;
4412 *destAlphaPtr
++ = (Guchar
)alpha
;
4418 gfree(alphaLineBuf
);
4423 void Splash::scaleImageYdXu(SplashImageSource src
, void *srcData
,
4424 SplashColorMode srcMode
, int nComps
,
4425 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4426 int scaledWidth
, int scaledHeight
,
4427 SplashBitmap
*dest
) {
4428 Guchar
*lineBuf
, *alphaLineBuf
;
4429 Guint
*pixBuf
, *alphaPixBuf
;
4430 Guint pix
[splashMaxColorComps
];
4432 Guchar
*destPtr
, *destAlphaPtr
;
4433 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, d
;
4436 // Bresenham parameters for y scale
4437 yp
= srcHeight
/ scaledHeight
;
4438 yq
= srcHeight
% scaledHeight
;
4440 // Bresenham parameters for x scale
4441 xp
= scaledWidth
/ srcWidth
;
4442 xq
= scaledWidth
% srcWidth
;
4445 lineBuf
= (Guchar
*)gmallocn(srcWidth
, nComps
);
4446 pixBuf
= (Guint
*)gmallocn(srcWidth
, nComps
* sizeof(int));
4448 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4449 alphaPixBuf
= (Guint
*)gmallocn(srcWidth
, sizeof(int));
4451 alphaLineBuf
= NULL
;
4455 // init y scale Bresenham
4458 destPtr
= dest
->data
;
4459 destAlphaPtr
= dest
->alpha
;
4460 for (y
= 0; y
< scaledHeight
; ++y
) {
4462 // y scale Bresenham
4463 if ((yt
+= yq
) >= scaledHeight
) {
4470 // read rows from image
4471 memset(pixBuf
, 0, srcWidth
* nComps
* sizeof(int));
4473 memset(alphaPixBuf
, 0, srcWidth
* sizeof(int));
4475 for (i
= 0; i
< yStep
; ++i
) {
4476 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4477 for (j
= 0; j
< srcWidth
* nComps
; ++j
) {
4478 pixBuf
[j
] += lineBuf
[j
];
4481 for (j
= 0; j
< srcWidth
; ++j
) {
4482 alphaPixBuf
[j
] += alphaLineBuf
[j
];
4487 // init x scale Bresenham
4489 d
= (1 << 23) / yStep
;
4491 for (x
= 0; x
< srcWidth
; ++x
) {
4493 // x scale Bresenham
4494 if ((xt
+= xq
) >= srcWidth
) {
4501 // compute the final pixel
4502 for (i
= 0; i
< nComps
; ++i
) {
4504 pix
[i
] = (pixBuf
[x
* nComps
+ i
] * d
) >> 23;
4509 case splashModeMono1
: // mono1 is not allowed
4511 case splashModeMono8
:
4512 for (i
= 0; i
< xStep
; ++i
) {
4513 *destPtr
++ = (Guchar
)pix
[0];
4516 case splashModeRGB8
:
4517 for (i
= 0; i
< xStep
; ++i
) {
4518 *destPtr
++ = (Guchar
)pix
[0];
4519 *destPtr
++ = (Guchar
)pix
[1];
4520 *destPtr
++ = (Guchar
)pix
[2];
4523 case splashModeXBGR8
:
4524 for (i
= 0; i
< xStep
; ++i
) {
4525 *destPtr
++ = (Guchar
)pix
[2];
4526 *destPtr
++ = (Guchar
)pix
[1];
4527 *destPtr
++ = (Guchar
)pix
[0];
4528 *destPtr
++ = (Guchar
)255;
4531 case splashModeBGR8
:
4532 for (i
= 0; i
< xStep
; ++i
) {
4533 *destPtr
++ = (Guchar
)pix
[2];
4534 *destPtr
++ = (Guchar
)pix
[1];
4535 *destPtr
++ = (Guchar
)pix
[0];
4539 case splashModeCMYK8
:
4540 for (i
= 0; i
< xStep
; ++i
) {
4541 *destPtr
++ = (Guchar
)pix
[0];
4542 *destPtr
++ = (Guchar
)pix
[1];
4543 *destPtr
++ = (Guchar
)pix
[2];
4544 *destPtr
++ = (Guchar
)pix
[3];
4547 case splashModeDeviceN8
:
4548 for (i
= 0; i
< xStep
; ++i
) {
4549 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4550 *destPtr
++ = (Guchar
)pix
[cp
];
4558 // alphaPixBuf[] / yStep
4559 alpha
= (alphaPixBuf
[x
] * d
) >> 23;
4560 for (i
= 0; i
< xStep
; ++i
) {
4561 *destAlphaPtr
++ = (Guchar
)alpha
;
4568 gfree(alphaLineBuf
);
4573 void Splash::scaleImageYuXd(SplashImageSource src
, void *srcData
,
4574 SplashColorMode srcMode
, int nComps
,
4575 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4576 int scaledWidth
, int scaledHeight
,
4577 SplashBitmap
*dest
) {
4578 Guchar
*lineBuf
, *alphaLineBuf
;
4579 Guint pix
[splashMaxColorComps
];
4581 Guchar
*destPtr0
, *destPtr
, *destAlphaPtr0
, *destAlphaPtr
;
4582 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
, xxa
, d
, d0
, d1
;
4585 // Bresenham parameters for y scale
4586 yp
= scaledHeight
/ srcHeight
;
4587 yq
= scaledHeight
% srcHeight
;
4589 // Bresenham parameters for x scale
4590 xp
= srcWidth
/ scaledWidth
;
4591 xq
= srcWidth
% scaledWidth
;
4594 lineBuf
= (Guchar
*)gmallocn_checkoverflow(srcWidth
, nComps
);
4595 if (unlikely(!lineBuf
))
4598 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4600 alphaLineBuf
= NULL
;
4603 // init y scale Bresenham
4606 destPtr0
= dest
->data
;
4607 destAlphaPtr0
= dest
->alpha
;
4608 for (y
= 0; y
< srcHeight
; ++y
) {
4610 // y scale Bresenham
4611 if ((yt
+= yq
) >= srcHeight
) {
4618 // read row from image
4619 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4621 // init x scale Bresenham
4623 d0
= (1 << 23) / xp
;
4624 d1
= (1 << 23) / (xp
+ 1);
4627 for (x
= 0; x
< scaledWidth
; ++x
) {
4629 // x scale Bresenham
4630 if ((xt
+= xq
) >= scaledWidth
) {
4639 // compute the final pixel
4640 for (i
= 0; i
< nComps
; ++i
) {
4643 for (i
= 0; i
< xStep
; ++i
) {
4644 for (j
= 0; j
< nComps
; ++j
, ++xx
) {
4645 pix
[j
] += lineBuf
[xx
];
4648 for (i
= 0; i
< nComps
; ++i
) {
4650 pix
[i
] = (pix
[i
] * d
) >> 23;
4655 case splashModeMono1
: // mono1 is not allowed
4657 case splashModeMono8
:
4658 for (i
= 0; i
< yStep
; ++i
) {
4659 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4660 *destPtr
++ = (Guchar
)pix
[0];
4663 case splashModeRGB8
:
4664 for (i
= 0; i
< yStep
; ++i
) {
4665 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4666 *destPtr
++ = (Guchar
)pix
[0];
4667 *destPtr
++ = (Guchar
)pix
[1];
4668 *destPtr
++ = (Guchar
)pix
[2];
4671 case splashModeXBGR8
:
4672 for (i
= 0; i
< yStep
; ++i
) {
4673 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4674 *destPtr
++ = (Guchar
)pix
[2];
4675 *destPtr
++ = (Guchar
)pix
[1];
4676 *destPtr
++ = (Guchar
)pix
[0];
4677 *destPtr
++ = (Guchar
)255;
4680 case splashModeBGR8
:
4681 for (i
= 0; i
< yStep
; ++i
) {
4682 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4683 *destPtr
++ = (Guchar
)pix
[2];
4684 *destPtr
++ = (Guchar
)pix
[1];
4685 *destPtr
++ = (Guchar
)pix
[0];
4689 case splashModeCMYK8
:
4690 for (i
= 0; i
< yStep
; ++i
) {
4691 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4692 *destPtr
++ = (Guchar
)pix
[0];
4693 *destPtr
++ = (Guchar
)pix
[1];
4694 *destPtr
++ = (Guchar
)pix
[2];
4695 *destPtr
++ = (Guchar
)pix
[3];
4698 case splashModeDeviceN8
:
4699 for (i
= 0; i
< yStep
; ++i
) {
4700 destPtr
= destPtr0
+ (i
* scaledWidth
+ x
) * nComps
;
4701 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4702 *destPtr
++ = (Guchar
)pix
[cp
];
4711 for (i
= 0; i
< xStep
; ++i
, ++xxa
) {
4712 alpha
+= alphaLineBuf
[xxa
];
4715 alpha
= (alpha
* d
) >> 23;
4716 for (i
= 0; i
< yStep
; ++i
) {
4717 destAlphaPtr
= destAlphaPtr0
+ i
* scaledWidth
+ x
;
4718 *destAlphaPtr
= (Guchar
)alpha
;
4723 destPtr0
+= yStep
* scaledWidth
* nComps
;
4725 destAlphaPtr0
+= yStep
* scaledWidth
;
4729 gfree(alphaLineBuf
);
4733 void Splash::scaleImageYuXu(SplashImageSource src
, void *srcData
,
4734 SplashColorMode srcMode
, int nComps
,
4735 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4736 int scaledWidth
, int scaledHeight
,
4737 SplashBitmap
*dest
) {
4738 Guchar
*lineBuf
, *alphaLineBuf
;
4739 Guint pix
[splashMaxColorComps
];
4741 Guchar
*destPtr0
, *destPtr
, *destAlphaPtr0
, *destAlphaPtr
;
4742 int yp
, yq
, xp
, xq
, yt
, y
, yStep
, xt
, x
, xStep
, xx
;
4745 // Bresenham parameters for y scale
4746 yp
= scaledHeight
/ srcHeight
;
4747 yq
= scaledHeight
% srcHeight
;
4749 // Bresenham parameters for x scale
4750 xp
= scaledWidth
/ srcWidth
;
4751 xq
= scaledWidth
% srcWidth
;
4754 lineBuf
= (Guchar
*)gmallocn(srcWidth
, nComps
);
4756 alphaLineBuf
= (Guchar
*)gmalloc(srcWidth
);
4758 alphaLineBuf
= NULL
;
4761 // init y scale Bresenham
4764 destPtr0
= dest
->data
;
4765 destAlphaPtr0
= dest
->alpha
;
4766 for (y
= 0; y
< srcHeight
; ++y
) {
4768 // y scale Bresenham
4769 if ((yt
+= yq
) >= srcHeight
) {
4776 // read row from image
4777 (*src
)(srcData
, lineBuf
, alphaLineBuf
);
4779 // init x scale Bresenham
4783 for (x
= 0; x
< srcWidth
; ++x
) {
4785 // x scale Bresenham
4786 if ((xt
+= xq
) >= srcWidth
) {
4793 // compute the final pixel
4794 for (i
= 0; i
< nComps
; ++i
) {
4795 pix
[i
] = lineBuf
[x
* nComps
+ i
];
4800 case splashModeMono1
: // mono1 is not allowed
4802 case splashModeMono8
:
4803 for (i
= 0; i
< yStep
; ++i
) {
4804 for (j
= 0; j
< xStep
; ++j
) {
4805 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4806 *destPtr
++ = (Guchar
)pix
[0];
4810 case splashModeRGB8
:
4811 for (i
= 0; i
< yStep
; ++i
) {
4812 for (j
= 0; j
< xStep
; ++j
) {
4813 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4814 *destPtr
++ = (Guchar
)pix
[0];
4815 *destPtr
++ = (Guchar
)pix
[1];
4816 *destPtr
++ = (Guchar
)pix
[2];
4820 case splashModeXBGR8
:
4821 for (i
= 0; i
< yStep
; ++i
) {
4822 for (j
= 0; j
< xStep
; ++j
) {
4823 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4824 *destPtr
++ = (Guchar
)pix
[2];
4825 *destPtr
++ = (Guchar
)pix
[1];
4826 *destPtr
++ = (Guchar
)pix
[0];
4827 *destPtr
++ = (Guchar
)255;
4831 case splashModeBGR8
:
4832 for (i
= 0; i
< yStep
; ++i
) {
4833 for (j
= 0; j
< xStep
; ++j
) {
4834 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4835 *destPtr
++ = (Guchar
)pix
[2];
4836 *destPtr
++ = (Guchar
)pix
[1];
4837 *destPtr
++ = (Guchar
)pix
[0];
4842 case splashModeCMYK8
:
4843 for (i
= 0; i
< yStep
; ++i
) {
4844 for (j
= 0; j
< xStep
; ++j
) {
4845 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4846 *destPtr
++ = (Guchar
)pix
[0];
4847 *destPtr
++ = (Guchar
)pix
[1];
4848 *destPtr
++ = (Guchar
)pix
[2];
4849 *destPtr
++ = (Guchar
)pix
[3];
4853 case splashModeDeviceN8
:
4854 for (i
= 0; i
< yStep
; ++i
) {
4855 for (j
= 0; j
< xStep
; ++j
) {
4856 destPtr
= destPtr0
+ (i
* scaledWidth
+ xx
+ j
) * nComps
;
4857 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
4858 *destPtr
++ = (Guchar
)pix
[cp
];
4867 alpha
= alphaLineBuf
[x
];
4868 for (i
= 0; i
< yStep
; ++i
) {
4869 for (j
= 0; j
< xStep
; ++j
) {
4870 destAlphaPtr
= destAlphaPtr0
+ i
* scaledWidth
+ xx
+ j
;
4871 *destAlphaPtr
= (Guchar
)alpha
;
4879 destPtr0
+= yStep
* scaledWidth
* nComps
;
4881 destAlphaPtr0
+= yStep
* scaledWidth
;
4885 gfree(alphaLineBuf
);
4889 // expand source row to scaledWidth using linear interpolation
4890 static void expandRow(Guchar
*srcBuf
, Guchar
*dstBuf
, int srcWidth
, int scaledWidth
, int nComps
)
4892 double xStep
= (double)srcWidth
/scaledWidth
;
4897 // pad the source with an extra pixel equal to the last pixel
4898 // so that when xStep is inside the last pixel we still have two
4899 // pixels to interpolate between.
4900 for (int i
= 0; i
< nComps
; i
++)
4901 srcBuf
[srcWidth
*nComps
+ i
] = srcBuf
[(srcWidth
-1)*nComps
+ i
];
4903 for (int x
= 0; x
< scaledWidth
; x
++) {
4904 xFrac
= modf(xSrc
, &xInt
);
4906 for (int c
= 0; c
< nComps
; c
++) {
4907 dstBuf
[nComps
*x
+ c
] = srcBuf
[nComps
*p
+ c
]*(1.0 - xFrac
) + srcBuf
[nComps
*(p
+1) + c
]*xFrac
;
4913 // Scale up image using bilinear interpolation
4914 void Splash::scaleImageYuXuBilinear(SplashImageSource src
, void *srcData
,
4915 SplashColorMode srcMode
, int nComps
,
4916 GBool srcAlpha
, int srcWidth
, int srcHeight
,
4917 int scaledWidth
, int scaledHeight
,
4918 SplashBitmap
*dest
) {
4919 Guchar
*srcBuf
, *lineBuf1
, *lineBuf2
, *alphaSrcBuf
, *alphaLineBuf1
, *alphaLineBuf2
;
4920 Guint pix
[splashMaxColorComps
];
4921 Guchar
*destPtr0
, *destPtr
, *destAlphaPtr0
, *destAlphaPtr
;
4924 if (srcWidth
< 1 || srcHeight
< 1)
4928 srcBuf
= (Guchar
*)gmallocn(srcWidth
+1, nComps
); // + 1 pixel of padding
4929 lineBuf1
= (Guchar
*)gmallocn(scaledWidth
, nComps
);
4930 lineBuf2
= (Guchar
*)gmallocn(scaledWidth
, nComps
);
4932 alphaSrcBuf
= (Guchar
*)gmalloc(srcWidth
+1); // + 1 pixel of padding
4933 alphaLineBuf1
= (Guchar
*)gmalloc(scaledWidth
);
4934 alphaLineBuf2
= (Guchar
*)gmalloc(scaledWidth
);
4937 alphaLineBuf1
= NULL
;
4938 alphaLineBuf2
= NULL
;
4942 double yStep
= (double)srcHeight
/scaledHeight
;
4944 int currentSrcRow
= -1;
4945 (*src
)(srcData
, srcBuf
, alphaSrcBuf
);
4946 expandRow(srcBuf
, lineBuf2
, srcWidth
, scaledWidth
, nComps
);
4948 expandRow(alphaSrcBuf
, alphaLineBuf2
, srcWidth
, scaledWidth
, 1);
4950 destPtr0
= dest
->data
;
4951 destAlphaPtr0
= dest
->alpha
;
4952 for (int y
= 0; y
< scaledHeight
; y
++) {
4953 yFrac
= modf(ySrc
, &yInt
);
4954 if ((int)yInt
> currentSrcRow
) {
4956 // Copy line2 data to line1 and get next line2 data.
4957 // If line2 already contains the last source row we don't touch it.
4958 // This effectively adds an extra row of padding for interpolating the
4959 // last source row with.
4960 memcpy(lineBuf1
, lineBuf2
, scaledWidth
* nComps
);
4962 memcpy(alphaLineBuf1
, alphaLineBuf2
, scaledWidth
);
4963 if (currentSrcRow
< srcHeight
) {
4964 (*src
)(srcData
, srcBuf
, alphaSrcBuf
);
4965 expandRow(srcBuf
, lineBuf2
, srcWidth
, scaledWidth
, nComps
);
4967 expandRow(alphaSrcBuf
, alphaLineBuf2
, srcWidth
, scaledWidth
, 1);
4971 // write row y using linear interpolation on lineBuf1 and lineBuf2
4972 for (int x
= 0; x
< scaledWidth
; ++x
) {
4973 // compute the final pixel
4974 for (i
= 0; i
< nComps
; ++i
) {
4975 pix
[i
] = lineBuf1
[x
*nComps
+ i
]*(1.0 - yFrac
) + lineBuf2
[x
*nComps
+ i
]*yFrac
;
4979 destPtr
= destPtr0
+ (y
* scaledWidth
+ x
) * nComps
;
4981 case splashModeMono1
: // mono1 is not allowed
4983 case splashModeMono8
:
4984 *destPtr
++ = (Guchar
)pix
[0];
4986 case splashModeRGB8
:
4987 *destPtr
++ = (Guchar
)pix
[0];
4988 *destPtr
++ = (Guchar
)pix
[1];
4989 *destPtr
++ = (Guchar
)pix
[2];
4991 case splashModeXBGR8
:
4992 *destPtr
++ = (Guchar
)pix
[2];
4993 *destPtr
++ = (Guchar
)pix
[1];
4994 *destPtr
++ = (Guchar
)pix
[0];
4995 *destPtr
++ = (Guchar
)255;
4997 case splashModeBGR8
:
4998 *destPtr
++ = (Guchar
)pix
[2];
4999 *destPtr
++ = (Guchar
)pix
[1];
5000 *destPtr
++ = (Guchar
)pix
[0];
5003 case splashModeCMYK8
:
5004 *destPtr
++ = (Guchar
)pix
[0];
5005 *destPtr
++ = (Guchar
)pix
[1];
5006 *destPtr
++ = (Guchar
)pix
[2];
5007 *destPtr
++ = (Guchar
)pix
[3];
5009 case splashModeDeviceN8
:
5010 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5011 *destPtr
++ = (Guchar
)pix
[cp
];
5018 destAlphaPtr
= destAlphaPtr0
+ y
*scaledWidth
+ x
;
5019 *destAlphaPtr
= alphaLineBuf1
[x
]*(1.0 - yFrac
) + alphaLineBuf2
[x
]*yFrac
;
5027 gfree(alphaLineBuf1
);
5028 gfree(alphaLineBuf2
);
5034 void Splash::vertFlipImage(SplashBitmap
*img
, int width
, int height
,
5040 if (unlikely(img
->data
== NULL
)) {
5041 error(errInternal
, -1, "img->data is NULL in Splash::vertFlipImage");
5046 lineBuf
= (Guchar
*)gmalloc(w
);
5047 for (p0
= img
->data
, p1
= img
->data
+ (height
- 1) * w
;
5050 memcpy(lineBuf
, p0
, w
);
5052 memcpy(p1
, lineBuf
, w
);
5055 for (p0
= img
->alpha
, p1
= img
->alpha
+ (height
- 1) * width
;
5057 p0
+= width
, p1
-= width
) {
5058 memcpy(lineBuf
, p0
, width
);
5059 memcpy(p0
, p1
, width
);
5060 memcpy(p1
, lineBuf
, width
);
5066 void Splash::blitImage(SplashBitmap
*src
, GBool srcAlpha
, int xDest
, int yDest
) {
5067 SplashClipResult clipRes
= state
->clip
->testRect(xDest
, yDest
, xDest
+ src
->getWidth() - 1, yDest
+ src
->getHeight() - 1);
5068 if (clipRes
!= splashClipAllOutside
) {
5069 blitImage(src
, srcAlpha
, xDest
, yDest
, clipRes
);
5073 void Splash::blitImage(SplashBitmap
*src
, GBool srcAlpha
, int xDest
, int yDest
,
5074 SplashClipResult clipRes
) {
5078 int w
, h
, x0
, y0
, x1
, y1
, x
, y
;
5080 // split the image into clipped and unclipped regions
5081 w
= src
->getWidth();
5082 h
= src
->getHeight();
5083 if (clipRes
== splashClipAllInside
) {
5089 if (state
->clip
->getNumPaths()) {
5093 if ((x0
= splashCeil(state
->clip
->getXMin()) - xDest
) < 0) {
5096 if ((y0
= splashCeil(state
->clip
->getYMin()) - yDest
) < 0) {
5099 if ((x1
= splashFloor(state
->clip
->getXMax()) - xDest
) > w
) {
5105 if ((y1
= splashFloor(state
->clip
->getYMax()) - yDest
) > h
) {
5114 // draw the unclipped region
5115 if (x0
< w
&& y0
< h
&& x0
< x1
&& y0
< y1
) {
5116 pipeInit(&pipe
, xDest
+ x0
, yDest
+ y0
, NULL
, pixel
,
5117 (Guchar
)splashRound(state
->fillAlpha
* 255), srcAlpha
, gFalse
);
5119 for (y
= y0
; y
< y1
; ++y
) {
5120 pipeSetXY(&pipe
, xDest
+ x0
, yDest
+ y
);
5121 ap
= src
->getAlphaPtr() + y
* w
+ x0
;
5122 for (x
= x0
; x
< x1
; ++x
) {
5123 src
->getPixel(x
, y
, pixel
);
5125 (this->*pipe
.run
)(&pipe
);
5129 for (y
= y0
; y
< y1
; ++y
) {
5130 pipeSetXY(&pipe
, xDest
+ x0
, yDest
+ y
);
5131 for (x
= x0
; x
< x1
; ++x
) {
5132 src
->getPixel(x
, y
, pixel
);
5133 (this->*pipe
.run
)(&pipe
);
5137 updateModX(xDest
+ x0
);
5138 updateModX(xDest
+ x1
- 1);
5139 updateModY(yDest
+ y0
);
5140 updateModY(yDest
+ y1
- 1);
5143 // draw the clipped regions
5145 blitImageClipped(src
, srcAlpha
, 0, 0, xDest
, yDest
, w
, y0
);
5148 blitImageClipped(src
, srcAlpha
, 0, y1
, xDest
, yDest
+ y1
, w
, h
- y1
);
5150 if (x0
> 0 && y0
< y1
) {
5151 blitImageClipped(src
, srcAlpha
, 0, y0
, xDest
, yDest
+ y0
, x0
, y1
- y0
);
5153 if (x1
< w
&& y0
< y1
) {
5154 blitImageClipped(src
, srcAlpha
, x1
, y0
, xDest
+ x1
, yDest
+ y0
,
5159 void Splash::blitImageClipped(SplashBitmap
*src
, GBool srcAlpha
,
5160 int xSrc
, int ySrc
, int xDest
, int yDest
,
5167 if (vectorAntialias
) {
5168 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5169 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, gFalse
);
5172 for (y
= 0; y
< h
; ++y
) {
5173 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5174 for (x
= 0; x
< w
; ++x
) {
5175 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5177 drawAAPixel(&pipe
, xDest
+ x
, yDest
+ y
);
5181 for (y
= 0; y
< h
; ++y
) {
5182 for (x
= 0; x
< w
; ++x
) {
5183 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5185 drawAAPixel(&pipe
, xDest
+ x
, yDest
+ y
);
5190 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5191 (Guchar
)splashRound(state
->fillAlpha
* 255), srcAlpha
, gFalse
);
5193 for (y
= 0; y
< h
; ++y
) {
5194 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5195 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5196 for (x
= 0; x
< w
; ++x
) {
5197 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5198 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5200 (this->*pipe
.run
)(&pipe
);
5201 updateModX(xDest
+ x
);
5202 updateModY(yDest
+ y
);
5210 for (y
= 0; y
< h
; ++y
) {
5211 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5212 for (x
= 0; x
< w
; ++x
) {
5213 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5214 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5215 (this->*pipe
.run
)(&pipe
);
5216 updateModX(xDest
+ x
);
5217 updateModY(yDest
+ y
);
5227 SplashError
Splash::composite(SplashBitmap
*src
, int xSrc
, int ySrc
,
5228 int xDest
, int yDest
, int w
, int h
,
5229 GBool noClip
, GBool nonIsolated
,
5230 GBool knockout
, SplashCoord knockoutOpacity
) {
5237 if (src
->mode
!= bitmap
->mode
) {
5238 return splashErrModeMismatch
;
5241 if (unlikely(!bitmap
->data
)) {
5242 return splashErrZeroImage
;
5245 if(src
->getSeparationList()->getLength() > bitmap
->getSeparationList()->getLength()) {
5246 for (x
= bitmap
->getSeparationList()->getLength(); x
< src
->getSeparationList()->getLength(); x
++)
5247 bitmap
->getSeparationList()->append(((GfxSeparationColorSpace
*)src
->getSeparationList()->get(x
))->copy());
5250 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5251 (Guchar
)splashRound(state
->fillAlpha
* 255), gTrue
, nonIsolated
,
5252 knockout
, (Guchar
)splashRound(knockoutOpacity
* 255));
5254 for (y
= 0; y
< h
; ++y
) {
5255 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5256 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5257 for (x
= 0; x
< w
; ++x
) {
5258 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5260 // this uses shape instead of alpha, which isn't technically
5261 // correct, but works out the same
5263 (this->*pipe
.run
)(&pipe
);
5267 updateModX(xDest
+ w
- 1);
5269 updateModY(yDest
+ h
- 1);
5271 for (y
= 0; y
< h
; ++y
) {
5272 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5273 ap
= src
->getAlphaPtr() + (ySrc
+ y
) * src
->getWidth() + xSrc
;
5274 for (x
= 0; x
< w
; ++x
) {
5275 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5277 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5278 // this uses shape instead of alpha, which isn't technically
5279 // correct, but works out the same
5281 (this->*pipe
.run
)(&pipe
);
5282 updateModX(xDest
+ x
);
5283 updateModY(yDest
+ y
);
5291 pipeInit(&pipe
, xDest
, yDest
, NULL
, pixel
,
5292 (Guchar
)splashRound(state
->fillAlpha
* 255), gFalse
, nonIsolated
);
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 (this->*pipe
.run
)(&pipe
);
5302 updateModX(xDest
+ w
- 1);
5304 updateModY(yDest
+ h
- 1);
5306 for (y
= 0; y
< h
; ++y
) {
5307 pipeSetXY(&pipe
, xDest
, yDest
+ y
);
5308 for (x
= 0; x
< w
; ++x
) {
5309 src
->getPixel(xSrc
+ x
, ySrc
+ y
, pixel
);
5310 if (state
->clip
->test(xDest
+ x
, yDest
+ y
)) {
5311 (this->*pipe
.run
)(&pipe
);
5312 updateModX(xDest
+ x
);
5313 updateModY(yDest
+ y
);
5325 void Splash::compositeBackground(SplashColorPtr color
) {
5328 Guchar alpha
, alpha1
, c
, color0
, color1
, color2
;
5331 Guchar colorsp
[SPOT_NCOMPS
+4], cp
;
5335 if (unlikely(bitmap
->alpha
== NULL
)) {
5336 error(errInternal
, -1, "bitmap->alpha is NULL in Splash::compositeBackground");
5340 switch (bitmap
->mode
) {
5341 case splashModeMono1
:
5343 for (y
= 0; y
< bitmap
->height
; ++y
) {
5344 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5345 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5347 for (x
= 0; x
< bitmap
->width
; ++x
) {
5349 alpha1
= 255 - alpha
;
5350 c
= (*p
& mask
) ? 0xff : 0x00;
5351 c
= div255(alpha1
* color0
+ alpha
* c
);
5357 if (!(mask
>>= 1)) {
5364 case splashModeMono8
:
5366 for (y
= 0; y
< bitmap
->height
; ++y
) {
5367 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5368 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5369 for (x
= 0; x
< bitmap
->width
; ++x
) {
5371 alpha1
= 255 - alpha
;
5372 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5377 case splashModeRGB8
:
5378 case splashModeBGR8
:
5382 for (y
= 0; y
< bitmap
->height
; ++y
) {
5383 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5384 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5385 for (x
= 0; x
< bitmap
->width
; ++x
) {
5393 else if (alpha
!= 255)
5395 alpha1
= 255 - alpha
;
5396 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5397 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
5398 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
5404 case splashModeXBGR8
:
5408 for (y
= 0; y
< bitmap
->height
; ++y
) {
5409 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5410 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5411 for (x
= 0; x
< bitmap
->width
; ++x
) {
5419 else if (alpha
!= 255)
5421 alpha1
= 255 - alpha
;
5422 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5423 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
5424 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
5432 case splashModeCMYK8
:
5437 for (y
= 0; y
< bitmap
->height
; ++y
) {
5438 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5439 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5440 for (x
= 0; x
< bitmap
->width
; ++x
) {
5449 else if (alpha
!= 255)
5451 alpha1
= 255 - alpha
;
5452 p
[0] = div255(alpha1
* color0
+ alpha
* p
[0]);
5453 p
[1] = div255(alpha1
* color1
+ alpha
* p
[1]);
5454 p
[2] = div255(alpha1
* color2
+ alpha
* p
[2]);
5455 p
[3] = div255(alpha1
* color3
+ alpha
* p
[3]);
5461 case splashModeDeviceN8
:
5462 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5463 colorsp
[cp
] = color
[cp
];
5464 for (y
= 0; y
< bitmap
->height
; ++y
) {
5465 p
= &bitmap
->data
[y
* bitmap
->rowSize
];
5466 q
= &bitmap
->alpha
[y
* bitmap
->width
];
5467 for (x
= 0; x
< bitmap
->width
; ++x
) {
5471 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5472 p
[cp
] = colorsp
[cp
];
5474 else if (alpha
!= 255)
5476 alpha1
= 255 - alpha
;
5477 for (cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
5478 p
[cp
] = div255(alpha1
* colorsp
[cp
] + alpha
* p
[cp
]);
5480 p
+= (SPOT_NCOMPS
+4);
5486 memset(bitmap
->alpha
, 255, bitmap
->width
* bitmap
->height
);
5489 GBool
Splash::gouraudTriangleShadedFill(SplashGouraudColor
*shading
)
5491 double xdbl
[3] = {0., 0., 0.};
5492 double ydbl
[3] = {0., 0., 0.};
5493 int x
[3] = {0, 0, 0};
5494 int y
[3] = {0, 0, 0};
5495 double xt
=0., xa
=0., yt
=0.;
5496 double ca
=0., ct
=0.;
5498 // triangle interpolation:
5500 double scanLimitMapL
[2] = {0., 0.};
5501 double scanLimitMapR
[2] = {0., 0.};
5502 double scanColorMapL
[2] = {0., 0.};
5503 double scanColorMapR
[2] = {0., 0.};
5504 double scanColorMap
[2] = {0., 0.};
5505 int scanEdgeL
[2] = { 0, 0 };
5506 int scanEdgeR
[2] = { 0, 0 };
5507 GBool hasFurtherSegment
= gFalse
;
5509 int scanLineOff
= 0;
5511 int scanLimitR
= 0, scanLimitL
= 0;
5513 int bitmapWidth
= bitmap
->getWidth();
5514 SplashClip
* clip
= getClip();
5515 SplashBitmap
*blitTarget
= bitmap
;
5516 SplashColorPtr bitmapData
= bitmap
->getDataPtr();
5517 int bitmapOffLimit
= bitmap
->getHeight() * bitmap
->getRowSize();
5518 SplashColorPtr bitmapAlpha
= bitmap
->getAlphaPtr();
5519 SplashColorPtr cur
= NULL
;
5520 SplashCoord
* userToCanvasMatrix
= getMatrix();
5521 SplashColorMode bitmapMode
= bitmap
->getMode();
5522 GBool hasAlpha
= (bitmapAlpha
!= NULL
);
5523 int rowSize
= bitmap
->getRowSize();
5525 switch (bitmapMode
) {
5526 case splashModeMono1
:
5528 case splashModeMono8
:
5531 case splashModeRGB8
:
5534 case splashModeBGR8
:
5537 case splashModeXBGR8
:
5541 case splashModeCMYK8
:
5544 case splashModeDeviceN8
:
5545 colorComps
=SPOT_NCOMPS
+4;
5551 SplashColor cSrcVal
;
5553 pipeInit(&pipe
, 0, 0, NULL
, cSrcVal
, (Guchar
)splashRound(state
->strokeAlpha
* 255), gFalse
, gFalse
);
5555 if (vectorAntialias
) {
5557 return gFalse
; // fall back to old behaviour
5562 // 1. If pipe->noTransparency && !state->blendFunc
5563 // -> blit directly into the drawing surface!
5564 // -> disable alpha manually.
5566 // - blit also directly, but into an intermediate surface.
5567 // Afterwards, blit the intermediate surface using the drawing pipeline.
5568 // This is necessary because triangle elements can be on top of each
5569 // other, so the complete shading needs to be drawn before opacity is
5571 // - the final step, is performed using a SplashPipe:
5572 // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
5573 // - invoke drawPixel(&pipe,X,Y,bNoClip);
5574 GBool bDirectBlit
= vectorAntialias
? gFalse
: pipe
.noTransparency
&& !state
->blendFunc
;
5576 blitTarget
= new SplashBitmap(bitmap
->getWidth(),
5577 bitmap
->getHeight(),
5578 bitmap
->getRowPad(),
5581 bitmap
->getRowSize() >= 0);
5582 bitmapData
= blitTarget
->getDataPtr();
5583 bitmapAlpha
= blitTarget
->getAlphaPtr();
5585 // initialisation seems to be necessary:
5586 int S
= bitmap
->getWidth() * bitmap
->getHeight();
5587 for (int i
= 0; i
< S
; ++i
)
5592 if (shading
->isParameterized()) {
5596 for (int i
= 0; i
< shading
->getNTriangles(); ++i
) {
5597 shading
->getTriangle(i
,
5598 xdbl
+ 0, ydbl
+ 0, color
+ 0,
5599 xdbl
+ 1, ydbl
+ 1, color
+ 1,
5600 xdbl
+ 2, ydbl
+ 2, color
+ 2);
5601 for (int m
= 0; m
< 3; ++m
) {
5602 xt
= xdbl
[m
] * (double)userToCanvasMatrix
[0] + ydbl
[m
] * (double)userToCanvasMatrix
[2] + (double)userToCanvasMatrix
[4];
5603 yt
= xdbl
[m
] * (double)userToCanvasMatrix
[1] + ydbl
[m
] * (double)userToCanvasMatrix
[3] + (double)userToCanvasMatrix
[5];
5606 // we operate on scanlines which are integer offsets into the
5607 // raster image. The double offsets are of no use here.
5608 x
[m
] = splashRound(xt
);
5609 y
[m
] = splashRound(yt
);
5611 // sort according to y coordinate to simplify sweep through scanlines:
5616 Guswap(color
[0], color
[1]);
5618 // first two are sorted.
5619 assert(y
[0] <= y
[1]);
5623 double tmpC
= color
[2];
5624 x
[2] = x
[1]; y
[2] = y
[1]; color
[2] = color
[1];
5627 x
[1] = x
[0]; y
[1] = y
[0]; color
[1] = color
[0];
5628 x
[0] = tmpX
; y
[0] = tmpY
; color
[0] = tmpC
;
5630 x
[1] = tmpX
; y
[1] = tmpY
; color
[1] = tmpC
;
5633 // first three are sorted
5634 assert(y
[0] <= y
[1]);
5635 assert(y
[1] <= y
[2]);
5638 // this here is det( T ) == 0
5639 // where T is the matrix to map to barycentric coordinates.
5640 if ((x
[0] - x
[2]) * (y
[1] - y
[2]) - (x
[1] - x
[2]) * (y
[0] - y
[2]) == 0)
5641 continue; // degenerate triangle.
5643 // this here initialises the scanline generation.
5644 // We start with low Y coordinates and sweep up to the large Y
5647 // scanEdgeL[m] in {0,1,2} m=0,1
5648 // scanEdgeR[m] in {0,1,2} m=0,1
5650 // are the two edges between which scanlines are (currently)
5651 // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
5652 // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
5658 scanEdgeL
[1] = scanEdgeR
[1] = 2;
5661 scanEdgeL
[1] = 1; scanEdgeR
[1] = 2;
5663 assert(y
[scanEdgeL
[0]] < y
[scanEdgeL
[1]]);
5664 assert(y
[scanEdgeR
[0]] < y
[scanEdgeR
[1]]);
5666 // Ok. Now prepare the linear maps which map the y coordinate of
5667 // the current scanline to the corresponding LEFT and RIGHT x
5668 // coordinate (which define the scanline).
5669 scanLimitMapL
[0] = double(x
[scanEdgeL
[1]] - x
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5670 scanLimitMapL
[1] = x
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanLimitMapL
[0];
5671 scanLimitMapR
[0] = double(x
[scanEdgeR
[1]] - x
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5672 scanLimitMapR
[1] = x
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanLimitMapR
[0];
5674 xa
= y
[1] * scanLimitMapL
[0] + scanLimitMapL
[1];
5675 xt
= y
[1] * scanLimitMapR
[0] + scanLimitMapR
[1];
5677 // I have "left" is to the right of "right".
5679 Guswap(scanEdgeL
[0], scanEdgeR
[0]);
5680 Guswap(scanEdgeL
[1], scanEdgeR
[1]);
5681 Guswap(scanLimitMapL
[0], scanLimitMapR
[0]);
5682 Guswap(scanLimitMapL
[1], scanLimitMapR
[1]);
5683 // FIXME I'm sure there is a more efficient way to check this.
5686 // Same game: we can linearly interpolate the color based on the
5687 // current y coordinate (that's correct for triangle
5688 // interpolation due to linearity. We could also have done it in
5689 // barycentric coordinates, but that's slightly more involved)
5690 scanColorMapL
[0] = (color
[scanEdgeL
[1]] - color
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5691 scanColorMapL
[1] = color
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanColorMapL
[0];
5692 scanColorMapR
[0] = (color
[scanEdgeR
[1]] - color
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5693 scanColorMapR
[1] = color
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanColorMapR
[0];
5695 hasFurtherSegment
= (y
[1] < y
[2]);
5696 scanLineOff
= y
[0] * rowSize
;
5698 for (int Y
= y
[0]; Y
<= y
[2]; ++Y
, scanLineOff
+= rowSize
) {
5699 if (hasFurtherSegment
&& Y
== y
[1]) {
5700 // SWEEP EVENT: we encountered the next segment.
5702 // switch to next segment, either at left end or at right
5704 if (scanEdgeL
[1] == 1) {
5707 scanLimitMapL
[0] = double(x
[scanEdgeL
[1]] - x
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5708 scanLimitMapL
[1] = x
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanLimitMapL
[0];
5710 scanColorMapL
[0] = (color
[scanEdgeL
[1]] - color
[scanEdgeL
[0]]) / (y
[scanEdgeL
[1]] - y
[scanEdgeL
[0]]);
5711 scanColorMapL
[1] = color
[scanEdgeL
[0]] - y
[scanEdgeL
[0]] * scanColorMapL
[0];
5712 } else if (scanEdgeR
[1] == 1) {
5715 scanLimitMapR
[0] = double(x
[scanEdgeR
[1]] - x
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5716 scanLimitMapR
[1] = x
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanLimitMapR
[0];
5718 scanColorMapR
[0] = (color
[scanEdgeR
[1]] - color
[scanEdgeR
[0]]) / (y
[scanEdgeR
[1]] - y
[scanEdgeR
[0]]);
5719 scanColorMapR
[1] = color
[scanEdgeR
[0]] - y
[scanEdgeR
[0]] * scanColorMapR
[0];
5721 assert( y
[scanEdgeL
[0]] < y
[scanEdgeL
[1]] );
5722 assert( y
[scanEdgeR
[0]] < y
[scanEdgeR
[1]] );
5723 hasFurtherSegment
= gFalse
;
5728 xa
= yt
* scanLimitMapL
[0] + scanLimitMapL
[1];
5729 xt
= yt
* scanLimitMapR
[0] + scanLimitMapR
[1];
5731 ca
= yt
* scanColorMapL
[0] + scanColorMapL
[1];
5732 ct
= yt
* scanColorMapR
[0] + scanColorMapR
[1];
5734 scanLimitL
= splashRound(xa
);
5735 scanLimitR
= splashRound(xt
);
5737 // Ok. Now: init the color interpolation depending on the X
5738 // coordinate inside of the current scanline:
5739 scanColorMap
[0] = (scanLimitR
== scanLimitL
) ? 0. : ((ct
- ca
) / (scanLimitR
- scanLimitL
));
5740 scanColorMap
[1] = ca
- scanLimitL
* scanColorMap
[0];
5742 // handled by clipping:
5743 // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
5744 assert(scanLimitL
<= scanLimitR
|| abs(scanLimitL
- scanLimitR
) <= 2); // allow rounding inaccuracies
5745 assert(scanLineOff
== Y
* rowSize
);
5747 colorinterp
= scanColorMap
[0] * scanLimitL
+ scanColorMap
[1];
5749 bitmapOff
= scanLineOff
+ scanLimitL
* colorComps
;
5750 for (int X
= scanLimitL
; X
<= scanLimitR
&& bitmapOff
+ colorComps
<= bitmapOffLimit
; ++X
, colorinterp
+= scanColorMap
[0], bitmapOff
+= colorComps
) {
5751 // FIXME : standard rectangular clipping can be done for a
5752 // complete scanline which is faster
5753 // --> see SplashClip and its methods
5754 if (!clip
->test(X
, Y
))
5757 assert(fabs(colorinterp
- (scanColorMap
[0] * X
+ scanColorMap
[1])) < 1e-10);
5758 assert(bitmapOff
== Y
* rowSize
+ colorComps
* X
&& scanLineOff
== Y
* rowSize
);
5760 shading
->getParameterizedColor(colorinterp
, bitmapMode
, &bitmapData
[bitmapOff
]);
5762 // make the shading visible.
5763 // Note that opacity is handled by the bDirectBlit stuff, see
5764 // above for comments and below for implementation.
5766 bitmapAlpha
[Y
* bitmapWidth
+ X
] = 255;
5775 // ok. Finalize the stuff by blitting the shading into the final
5776 // geometry, this time respecting the rendering pipe.
5777 int W
= blitTarget
->getWidth();
5778 int H
= blitTarget
->getHeight();
5781 for (int X
= 0; X
< W
; ++X
) {
5782 for (int Y
= 0; Y
< H
; ++Y
) {
5783 if (!bitmapAlpha
[Y
* bitmapWidth
+ X
])
5784 continue; // draw only parts of the shading!
5785 bitmapOff
= Y
* rowSize
+ colorComps
* X
;
5787 for (int m
= 0; m
< colorComps
; ++m
)
5788 cur
[m
] = bitmapData
[bitmapOff
+ m
];
5789 if (vectorAntialias
) {
5790 drawAAPixel(&pipe
, X
, Y
);
5792 drawPixel(&pipe
, X
, Y
, gTrue
); // no clipping - has already been done.
5804 SplashError
Splash::blitTransparent(SplashBitmap
*src
, int xSrc
, int ySrc
,
5805 int xDest
, int yDest
, int w
, int h
) {
5806 SplashColorPtr p
, sp
;
5808 int x
, y
, mask
, srcMask
;
5810 if (src
->mode
!= bitmap
->mode
) {
5811 return splashErrModeMismatch
;
5814 if (unlikely(!bitmap
->data
)) {
5815 return splashErrZeroImage
;
5818 switch (bitmap
->mode
) {
5819 case splashModeMono1
:
5820 for (y
= 0; y
< h
; ++y
) {
5821 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ (xDest
>> 3)];
5822 mask
= 0x80 >> (xDest
& 7);
5823 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ (xSrc
>> 3)];
5824 srcMask
= 0x80 >> (xSrc
& 7);
5825 for (x
= 0; x
< w
; ++x
) {
5826 if (*sp
& srcMask
) {
5831 if (!(mask
>>= 1)) {
5835 if (!(srcMask
>>= 1)) {
5842 case splashModeMono8
:
5843 for (y
= 0; y
< h
; ++y
) {
5844 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ xDest
];
5845 sp
= &src
->data
[(ySrc
+ y
) * bitmap
->rowSize
+ xSrc
];
5846 for (x
= 0; x
< w
; ++x
) {
5851 case splashModeRGB8
:
5852 case splashModeBGR8
:
5853 for (y
= 0; y
< h
; ++y
) {
5854 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 3 * xDest
];
5855 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ 3 * xSrc
];
5856 for (x
= 0; x
< w
; ++x
) {
5863 case splashModeXBGR8
:
5864 for (y
= 0; y
< h
; ++y
) {
5865 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 4 * xDest
];
5866 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ 4 * xSrc
];
5867 for (x
= 0; x
< w
; ++x
) {
5877 case splashModeCMYK8
:
5878 for (y
= 0; y
< h
; ++y
) {
5879 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ 4 * xDest
];
5880 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ 4 * xSrc
];
5881 for (x
= 0; x
< w
; ++x
) {
5889 case splashModeDeviceN8
:
5890 for (y
= 0; y
< h
; ++y
) {
5891 p
= &bitmap
->data
[(yDest
+ y
) * bitmap
->rowSize
+ (SPOT_NCOMPS
+4) * xDest
];
5892 sp
= &src
->data
[(ySrc
+ y
) * src
->rowSize
+ (SPOT_NCOMPS
+4) * xSrc
];
5893 for (x
= 0; x
< w
; ++x
) {
5894 for (int cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
5902 if (bitmap
->alpha
) {
5903 for (y
= 0; y
< h
; ++y
) {
5904 q
= &bitmap
->alpha
[(yDest
+ y
) * bitmap
->width
+ xDest
];
5912 SplashPath
*Splash::makeStrokePath(SplashPath
*path
, SplashCoord w
,
5914 SplashPath
*pathIn
, *dashPath
, *pathOut
;
5915 SplashCoord d
, dx
, dy
, wdx
, wdy
, dxNext
, dyNext
, wdxNext
, wdyNext
;
5916 SplashCoord crossprod
, dotprod
, miter
, m
;
5917 GBool first
, last
, closed
;
5918 int subpathStart0
, subpathStart1
, seg
, i0
, i1
, j0
, j1
, k0
, k1
;
5919 int left0
, left1
, left2
, right0
, right1
, right2
, join0
, join1
, join2
;
5920 int leftFirst
, rightFirst
, firstPt
;
5922 pathOut
= new SplashPath();
5924 if (path
->length
== 0) {
5929 pathIn
= flattenPath(path
, state
->matrix
, state
->flatness
);
5930 if (state
->lineDashLength
> 0) {
5931 dashPath
= makeDashedPath(pathIn
);
5934 if (pathIn
->length
== 0) {
5943 subpathStart0
= subpathStart1
= 0; // make gcc happy
5944 seg
= 0; // make gcc happy
5945 closed
= gFalse
; // make gcc happy
5946 left0
= left1
= right0
= right1
= join0
= join1
= 0; // make gcc happy
5947 leftFirst
= rightFirst
= firstPt
= 0; // make gcc happy
5951 !(pathIn
->flags
[i1
] & splashPathLast
) &&
5952 i1
+ 1 < pathIn
->length
&&
5953 pathIn
->pts
[i1
+1].x
== pathIn
->pts
[i1
].x
&&
5954 pathIn
->pts
[i1
+1].y
== pathIn
->pts
[i1
].y
;
5957 while (i1
< pathIn
->length
) {
5958 if ((first
= pathIn
->flags
[i0
] & splashPathFirst
)) {
5962 closed
= pathIn
->flags
[i0
] & splashPathClosed
;
5965 if (j0
< pathIn
->length
) {
5967 !(pathIn
->flags
[j1
] & splashPathLast
) &&
5968 j1
+ 1 < pathIn
->length
&&
5969 pathIn
->pts
[j1
+1].x
== pathIn
->pts
[j1
].x
&&
5970 pathIn
->pts
[j1
+1].y
== pathIn
->pts
[j1
].y
;
5975 if (pathIn
->flags
[i1
] & splashPathLast
) {
5976 if (first
&& state
->lineCap
== splashLineCapRound
) {
5977 // special case: zero-length subpath with round line caps -->
5979 pathOut
->moveTo(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
,
5993 pathOut
->curveTo(pathIn
->pts
[i0
].x
- (SplashCoord
)0.5 * w
,
5994 pathIn
->pts
[i0
].y
- bezierCircle2
* w
,
5995 pathIn
->pts
[i0
].x
- bezierCircle2
* w
,
5996 pathIn
->pts
[i0
].y
- (SplashCoord
)0.5 * w
,
5998 pathIn
->pts
[i0
].y
- (SplashCoord
)0.5 * w
);
5999 pathOut
->curveTo(pathIn
->pts
[i0
].x
+ bezierCircle2
* w
,
6000 pathIn
->pts
[i0
].y
- (SplashCoord
)0.5 * w
,
6001 pathIn
->pts
[i0
].x
+ (SplashCoord
)0.5 * w
,
6002 pathIn
->pts
[i0
].y
- bezierCircle2
* w
,
6003 pathIn
->pts
[i0
].x
+ (SplashCoord
)0.5 * w
,
6011 last
= pathIn
->flags
[j1
] & splashPathLast
;
6013 k0
= subpathStart1
+ 1;
6018 !(pathIn
->flags
[k1
] & splashPathLast
) &&
6019 k1
+ 1 < pathIn
->length
&&
6020 pathIn
->pts
[k1
+1].x
== pathIn
->pts
[k1
].x
&&
6021 pathIn
->pts
[k1
+1].y
== pathIn
->pts
[k1
].y
;
6024 // compute the deltas for segment (i1, j0)
6026 // the 1/d value can be small, which introduces significant
6027 // inaccuracies in fixed point mode
6028 d
= splashDist(pathIn
->pts
[i1
].x
, pathIn
->pts
[i1
].y
,
6029 pathIn
->pts
[j0
].x
, pathIn
->pts
[j0
].y
);
6030 dx
= (pathIn
->pts
[j0
].x
- pathIn
->pts
[i1
].x
) / d
;
6031 dy
= (pathIn
->pts
[j0
].y
- pathIn
->pts
[i1
].y
) / d
;
6033 d
= (SplashCoord
)1 / splashDist(pathIn
->pts
[i1
].x
, pathIn
->pts
[i1
].y
,
6034 pathIn
->pts
[j0
].x
, pathIn
->pts
[j0
].y
);
6035 dx
= d
* (pathIn
->pts
[j0
].x
- pathIn
->pts
[i1
].x
);
6036 dy
= d
* (pathIn
->pts
[j0
].y
- pathIn
->pts
[i1
].y
);
6038 wdx
= (SplashCoord
)0.5 * w
* dx
;
6039 wdy
= (SplashCoord
)0.5 * w
* dy
;
6041 // draw the start cap
6042 pathOut
->moveTo(pathIn
->pts
[i0
].x
- wdy
, pathIn
->pts
[i0
].y
+ wdx
);
6043 if (i0
== subpathStart0
) {
6044 firstPt
= pathOut
->length
- 1;
6046 if (first
&& !closed
) {
6047 switch (state
->lineCap
) {
6048 case splashLineCapButt
:
6049 pathOut
->lineTo(pathIn
->pts
[i0
].x
+ wdy
, pathIn
->pts
[i0
].y
- wdx
);
6051 case splashLineCapRound
:
6052 pathOut
->curveTo(pathIn
->pts
[i0
].x
- wdy
- bezierCircle
* wdx
,
6053 pathIn
->pts
[i0
].y
+ wdx
- bezierCircle
* wdy
,
6054 pathIn
->pts
[i0
].x
- wdx
- bezierCircle
* wdy
,
6055 pathIn
->pts
[i0
].y
- wdy
+ bezierCircle
* wdx
,
6056 pathIn
->pts
[i0
].x
- wdx
,
6057 pathIn
->pts
[i0
].y
- wdy
);
6058 pathOut
->curveTo(pathIn
->pts
[i0
].x
- wdx
+ bezierCircle
* wdy
,
6059 pathIn
->pts
[i0
].y
- wdy
- bezierCircle
* wdx
,
6060 pathIn
->pts
[i0
].x
+ wdy
- bezierCircle
* wdx
,
6061 pathIn
->pts
[i0
].y
- wdx
- bezierCircle
* wdy
,
6062 pathIn
->pts
[i0
].x
+ wdy
,
6063 pathIn
->pts
[i0
].y
- wdx
);
6065 case splashLineCapProjecting
:
6066 pathOut
->lineTo(pathIn
->pts
[i0
].x
- wdx
- wdy
,
6067 pathIn
->pts
[i0
].y
+ wdx
- wdy
);
6068 pathOut
->lineTo(pathIn
->pts
[i0
].x
- wdx
+ wdy
,
6069 pathIn
->pts
[i0
].y
- wdx
- wdy
);
6070 pathOut
->lineTo(pathIn
->pts
[i0
].x
+ wdy
,
6071 pathIn
->pts
[i0
].y
- wdx
);
6075 pathOut
->lineTo(pathIn
->pts
[i0
].x
+ wdy
, pathIn
->pts
[i0
].y
- wdx
);
6078 // draw the left side of the segment rectangle
6079 left2
= pathOut
->length
- 1;
6080 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
, pathIn
->pts
[j0
].y
- wdx
);
6083 if (last
&& !closed
) {
6084 switch (state
->lineCap
) {
6085 case splashLineCapButt
:
6086 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
, pathIn
->pts
[j0
].y
+ wdx
);
6088 case splashLineCapRound
:
6089 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ wdy
+ bezierCircle
* wdx
,
6090 pathIn
->pts
[j0
].y
- wdx
+ bezierCircle
* wdy
,
6091 pathIn
->pts
[j0
].x
+ wdx
+ bezierCircle
* wdy
,
6092 pathIn
->pts
[j0
].y
+ wdy
- bezierCircle
* wdx
,
6093 pathIn
->pts
[j0
].x
+ wdx
,
6094 pathIn
->pts
[j0
].y
+ wdy
);
6095 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ wdx
- bezierCircle
* wdy
,
6096 pathIn
->pts
[j0
].y
+ wdy
+ bezierCircle
* wdx
,
6097 pathIn
->pts
[j0
].x
- wdy
+ bezierCircle
* wdx
,
6098 pathIn
->pts
[j0
].y
+ wdx
+ bezierCircle
* wdy
,
6099 pathIn
->pts
[j0
].x
- wdy
,
6100 pathIn
->pts
[j0
].y
+ wdx
);
6102 case splashLineCapProjecting
:
6103 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
+ wdx
,
6104 pathIn
->pts
[j0
].y
- wdx
+ wdy
);
6105 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
+ wdx
,
6106 pathIn
->pts
[j0
].y
+ wdx
+ wdy
);
6107 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
,
6108 pathIn
->pts
[j0
].y
+ wdx
);
6112 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
, pathIn
->pts
[j0
].y
+ wdx
);
6115 // draw the right side of the segment rectangle
6116 // (NB: if stroke adjustment is enabled, the closepath operation MUST
6117 // add a segment because this segment is used for a hint)
6118 right2
= pathOut
->length
- 1;
6119 pathOut
->close(state
->strokeAdjust
);
6122 join2
= pathOut
->length
;
6123 if (!last
|| closed
) {
6125 // compute the deltas for segment (j1, k0)
6127 // the 1/d value can be small, which introduces significant
6128 // inaccuracies in fixed point mode
6129 d
= splashDist(pathIn
->pts
[j1
].x
, pathIn
->pts
[j1
].y
,
6130 pathIn
->pts
[k0
].x
, pathIn
->pts
[k0
].y
);
6131 dxNext
= (pathIn
->pts
[k0
].x
- pathIn
->pts
[j1
].x
) / d
;
6132 dyNext
= (pathIn
->pts
[k0
].y
- pathIn
->pts
[j1
].y
) / d
;
6134 d
= (SplashCoord
)1 / splashDist(pathIn
->pts
[j1
].x
, pathIn
->pts
[j1
].y
,
6135 pathIn
->pts
[k0
].x
, pathIn
->pts
[k0
].y
);
6136 dxNext
= d
* (pathIn
->pts
[k0
].x
- pathIn
->pts
[j1
].x
);
6137 dyNext
= d
* (pathIn
->pts
[k0
].y
- pathIn
->pts
[j1
].y
);
6139 wdxNext
= (SplashCoord
)0.5 * w
* dxNext
;
6140 wdyNext
= (SplashCoord
)0.5 * w
* dyNext
;
6142 // compute the join parameters
6143 crossprod
= dx
* dyNext
- dy
* dxNext
;
6144 dotprod
= -(dx
* dxNext
+ dy
* dyNext
);
6145 if (dotprod
> 0.9999) {
6146 // avoid a divide-by-zero -- set miter to something arbitrary
6147 // such that sqrt(miter) will exceed miterLimit (and m is never
6148 // used in that situation)
6149 // (note: the comparison value (0.9999) has to be less than
6150 // 1-epsilon, where epsilon is the smallest value
6151 // representable in the fixed point format)
6152 miter
= (state
->miterLimit
+ 1) * (state
->miterLimit
+ 1);
6155 miter
= (SplashCoord
)2 / ((SplashCoord
)1 - dotprod
);
6157 // this can happen because of floating point inaccuracies
6160 m
= splashSqrt(miter
- 1);
6164 if (state
->lineJoin
== splashLineJoinRound
) {
6165 pathOut
->moveTo(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
,
6179 pathOut
->curveTo(pathIn
->pts
[j0
].x
- (SplashCoord
)0.5 * w
,
6180 pathIn
->pts
[j0
].y
- bezierCircle2
* w
,
6181 pathIn
->pts
[j0
].x
- bezierCircle2
* w
,
6182 pathIn
->pts
[j0
].y
- (SplashCoord
)0.5 * w
,
6184 pathIn
->pts
[j0
].y
- (SplashCoord
)0.5 * w
);
6185 pathOut
->curveTo(pathIn
->pts
[j0
].x
+ bezierCircle2
* w
,
6186 pathIn
->pts
[j0
].y
- (SplashCoord
)0.5 * w
,
6187 pathIn
->pts
[j0
].x
+ (SplashCoord
)0.5 * w
,
6188 pathIn
->pts
[j0
].y
- bezierCircle2
* w
,
6189 pathIn
->pts
[j0
].x
+ (SplashCoord
)0.5 * w
,
6193 pathOut
->moveTo(pathIn
->pts
[j0
].x
, pathIn
->pts
[j0
].y
);
6196 if (crossprod
< 0) {
6197 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdyNext
,
6198 pathIn
->pts
[j0
].y
+ wdxNext
);
6199 // miter join inside limit
6200 if (state
->lineJoin
== splashLineJoinMiter
&&
6201 splashSqrt(miter
) <= state
->miterLimit
) {
6202 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
+ wdx
* m
,
6203 pathIn
->pts
[j0
].y
+ wdx
+ wdy
* m
);
6204 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
,
6205 pathIn
->pts
[j0
].y
+ wdx
);
6206 // bevel join or miter join outside limit
6208 pathOut
->lineTo(pathIn
->pts
[j0
].x
- wdy
,
6209 pathIn
->pts
[j0
].y
+ wdx
);
6214 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
,
6215 pathIn
->pts
[j0
].y
- wdx
);
6216 // miter join inside limit
6217 if (state
->lineJoin
== splashLineJoinMiter
&&
6218 splashSqrt(miter
) <= state
->miterLimit
) {
6219 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdy
+ wdx
* m
,
6220 pathIn
->pts
[j0
].y
- wdx
+ wdy
* m
);
6221 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdyNext
,
6222 pathIn
->pts
[j0
].y
- wdxNext
);
6223 // bevel join or miter join outside limit
6225 pathOut
->lineTo(pathIn
->pts
[j0
].x
+ wdyNext
,
6226 pathIn
->pts
[j0
].y
- wdxNext
);
6234 // add stroke adjustment hints
6235 if (state
->strokeAdjust
) {
6236 if (seg
== 0 && !closed
) {
6237 if (state
->lineCap
== splashLineCapButt
) {
6238 pathOut
->addStrokeAdjustHint(firstPt
, left2
+ 1,
6239 firstPt
, firstPt
+ 1);
6241 pathOut
->addStrokeAdjustHint(firstPt
, left2
+ 1,
6242 left2
+ 1, left2
+ 2);
6244 } else if (state
->lineCap
== splashLineCapProjecting
) {
6246 pathOut
->addStrokeAdjustHint(firstPt
+ 1, left2
+ 2,
6247 firstPt
+ 1, firstPt
+ 2);
6248 pathOut
->addStrokeAdjustHint(firstPt
+ 1, left2
+ 2,
6249 left2
+ 2, left2
+ 3);
6251 pathOut
->addStrokeAdjustHint(firstPt
+ 1, left2
+ 1,
6252 firstPt
+ 1, firstPt
+ 2);
6258 pathOut
->addStrokeAdjustHint(left1
, right1
, left0
+ 1, right0
);
6259 pathOut
->addStrokeAdjustHint(left1
, right1
, join0
, left2
);
6261 pathOut
->addStrokeAdjustHint(left1
, right1
, firstPt
, left2
);
6263 pathOut
->addStrokeAdjustHint(left1
, right1
, right2
+ 1, right2
+ 1);
6273 rightFirst
= right2
;
6277 pathOut
->addStrokeAdjustHint(left1
, right1
, left0
+ 1, right0
);
6278 pathOut
->addStrokeAdjustHint(left1
, right1
,
6279 join0
, pathOut
->length
- 1);
6281 pathOut
->addStrokeAdjustHint(left1
, right1
,
6282 firstPt
, pathOut
->length
- 1);
6285 pathOut
->addStrokeAdjustHint(left1
, right1
, firstPt
, leftFirst
);
6286 pathOut
->addStrokeAdjustHint(left1
, right1
,
6287 rightFirst
+ 1, rightFirst
+ 1);
6288 pathOut
->addStrokeAdjustHint(leftFirst
, rightFirst
,
6290 pathOut
->addStrokeAdjustHint(leftFirst
, rightFirst
,
6291 join1
, pathOut
->length
- 1);
6293 if (!closed
&& seg
> 0) {
6294 if (state
->lineCap
== splashLineCapButt
) {
6295 pathOut
->addStrokeAdjustHint(left1
- 1, left1
+ 1,
6296 left1
+ 1, left1
+ 2);
6297 } else if (state
->lineCap
== splashLineCapProjecting
) {
6298 pathOut
->addStrokeAdjustHint(left1
- 1, left1
+ 2,
6299 left1
+ 2, left1
+ 3);
6310 if (pathIn
!= path
) {
6317 void Splash::dumpPath(SplashPath
*path
) {
6320 for (i
= 0; i
< path
->length
; ++i
) {
6321 printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
6322 i
, (double)path
->pts
[i
].x
, (double)path
->pts
[i
].y
,
6323 (path
->flags
[i
] & splashPathFirst
) ? " first" : "",
6324 (path
->flags
[i
] & splashPathLast
) ? " last" : "",
6325 (path
->flags
[i
] & splashPathClosed
) ? " closed" : "",
6326 (path
->flags
[i
] & splashPathCurve
) ? " curve" : "");
6330 void Splash::dumpXPath(SplashXPath
*path
) {
6333 for (i
= 0; i
< path
->length
; ++i
) {
6334 printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n",
6335 i
, (double)path
->segs
[i
].x0
, (double)path
->segs
[i
].y0
,
6336 (double)path
->segs
[i
].x1
, (double)path
->segs
[i
].y1
,
6337 (path
->segs
[i
].flags
& splashXPathHoriz
) ? "H" : " ",
6338 (path
->segs
[i
].flags
& splashXPathVert
) ? "V" : " ",
6339 (path
->segs
[i
].flags
& splashXPathFlip
) ? "P" : " ");
6343 SplashError
Splash::shadedFill(SplashPath
*path
, GBool hasBBox
,
6344 SplashPattern
*pattern
) {
6347 SplashXPathScanner
*scanner
;
6348 int xMinI
, yMinI
, xMaxI
, yMaxI
, x0
, x1
, y
;
6349 SplashClipResult clipRes
;
6351 if (vectorAntialias
&& aaBuf
== NULL
) { // should not happen, but to be secure
6352 return splashErrGeneric
;
6354 if (path
->length
== 0) {
6355 return splashErrEmptyPath
;
6357 xPath
= new SplashXPath(path
, state
->matrix
, state
->flatness
, gTrue
);
6358 if (vectorAntialias
) {
6362 yMinI
= state
->clip
->getYMinI();
6363 yMaxI
= state
->clip
->getYMaxI();
6364 if (vectorAntialias
&& !inShading
) {
6365 yMinI
= yMinI
* splashAASize
;
6366 yMaxI
= (yMaxI
+ 1) * splashAASize
- 1;
6368 scanner
= new SplashXPathScanner(xPath
, gFalse
, yMinI
, yMaxI
);
6370 // get the min and max x and y values
6371 if (vectorAntialias
) {
6372 scanner
->getBBoxAA(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
6374 scanner
->getBBox(&xMinI
, &yMinI
, &xMaxI
, &yMaxI
);
6378 if ((clipRes
= state
->clip
->testRect(xMinI
, yMinI
, xMaxI
, yMaxI
)) != splashClipAllOutside
) {
6379 // limit the y range
6380 if (yMinI
< state
->clip
->getYMinI()) {
6381 yMinI
= state
->clip
->getYMinI();
6383 if (yMaxI
> state
->clip
->getYMaxI()) {
6384 yMaxI
= state
->clip
->getYMaxI();
6387 pipeInit(&pipe
, 0, yMinI
, pattern
, NULL
, (Guchar
)splashRound(state
->fillAlpha
* 255), vectorAntialias
&& !hasBBox
, gFalse
);
6390 if (vectorAntialias
) {
6391 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
6392 scanner
->renderAALine(aaBuf
, &x0
, &x1
, y
);
6393 if (clipRes
!= splashClipAllInside
) {
6394 state
->clip
->clipAALine(aaBuf
, &x0
, &x1
, y
);
6396 #if splashAASize == 4
6397 if (!hasBBox
&& y
> yMinI
&& y
< yMaxI
) {
6398 // correct shape on left side if clip is
6399 // vertical through the middle of shading:
6400 Guchar
*p0
, *p1
, *p2
, *p3
;
6401 Guchar c1
, c2
, c3
, c4
;
6402 p0
= aaBuf
->getDataPtr() + (x0
>> 1);
6403 p1
= p0
+ aaBuf
->getRowSize();
6404 p2
= p1
+ aaBuf
->getRowSize();
6405 p3
= p2
+ aaBuf
->getRowSize();
6407 c1
= (*p0
& 0x0f); c2
=(*p1
& 0x0f); c3
= (*p2
& 0x0f) ; c4
= (*p3
& 0x0f);
6409 c1
= (*p0
>> 4); c2
= (*p1
>> 4); c3
= (*p2
>> 4); c4
= (*p3
>> 4);
6411 if ( (c1
& 0x03) == 0x03 && (c2
& 0x03) == 0x03 && (c3
& 0x03) == 0x03 && (c4
& 0x03) == 0x03
6412 && c1
== c2
&& c2
== c3
&& c3
== c4
&&
6413 pattern
->testPosition(x0
- 1, y
) )
6415 Guchar shapeCorrection
= (x0
& 1) ? 0x0f : 0xf0;
6416 *p0
|= shapeCorrection
;
6417 *p1
|= shapeCorrection
;
6418 *p2
|= shapeCorrection
;
6419 *p3
|= shapeCorrection
;
6421 // correct shape on right side if clip is
6422 // through the middle of shading:
6423 p0
= aaBuf
->getDataPtr() + (x1
>> 1);
6424 p1
= p0
+ aaBuf
->getRowSize();
6425 p2
= p1
+ aaBuf
->getRowSize();
6426 p3
= p2
+ aaBuf
->getRowSize();
6428 c1
= (*p0
& 0x0f); c2
=(*p1
& 0x0f); c3
= (*p2
& 0x0f) ; c4
= (*p3
& 0x0f);
6430 c1
= (*p0
>> 4); c2
= (*p1
>> 4); c3
= (*p2
>> 4); c4
= (*p3
>> 4);
6433 if ( (c1
& 0xc) == 0x0c && (c2
& 0x0c) == 0x0c && (c3
& 0x0c) == 0x0c && (c4
& 0x0c) == 0x0c
6434 && c1
== c2
&& c2
== c3
&& c3
== c4
&&
6435 pattern
->testPosition(x1
+ 1, y
) )
6437 Guchar shapeCorrection
= (x1
& 1) ? 0x0f : 0xf0;
6438 *p0
|= shapeCorrection
;
6439 *p1
|= shapeCorrection
;
6440 *p2
|= shapeCorrection
;
6441 *p3
|= shapeCorrection
;
6445 drawAALine(&pipe
, x0
, x1
, y
);
6448 SplashClipResult clipRes2
;
6449 for (y
= yMinI
; y
<= yMaxI
; ++y
) {
6450 while (scanner
->getNextSpan(y
, &x0
, &x1
)) {
6451 if (clipRes
== splashClipAllInside
) {
6452 drawSpan(&pipe
, x0
, x1
, y
, gTrue
);
6454 // limit the x range
6455 if (x0
< state
->clip
->getXMinI()) {
6456 x0
= state
->clip
->getXMinI();
6458 if (x1
> state
->clip
->getXMaxI()) {
6459 x1
= state
->clip
->getXMaxI();
6461 clipRes2
= state
->clip
->testSpan(x0
, x1
, y
);
6462 drawSpan(&pipe
, x0
, x1
, y
, clipRes2
== splashClipAllInside
);
6468 opClipRes
= clipRes
;