]> git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/Splash.cxx
Load cups into easysw/current.
[thirdparty/cups.git] / pdftops / Splash.cxx
1 //========================================================================
2 //
3 // Splash.cc
4 //
5 //========================================================================
6
7 #include <config.h>
8
9 #ifdef USE_GCC_PRAGMAS
10 #pragma implementation
11 #endif
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include "gmem.h"
16 #include "SplashErrorCodes.h"
17 #include "SplashMath.h"
18 #include "SplashBitmap.h"
19 #include "SplashState.h"
20 #include "SplashPath.h"
21 #include "SplashXPath.h"
22 #include "SplashXPathScanner.h"
23 #include "SplashPattern.h"
24 #include "SplashScreen.h"
25 #include "SplashFont.h"
26 #include "SplashGlyphBitmap.h"
27 #include "Splash.h"
28
29 //------------------------------------------------------------------------
30
31 static void blendNormal(SplashColorPtr src, SplashColorPtr dest,
32 SplashColorPtr blend, SplashColorMode cm) {
33 int i;
34
35 for (i = 0; i < splashColorModeNComps[cm]; ++i) {
36 blend[i] = src[i];
37 }
38 }
39
40 //------------------------------------------------------------------------
41 // Splash
42 //------------------------------------------------------------------------
43
44 Splash::Splash(SplashBitmap *bitmapA) {
45 bitmap = bitmapA;
46 state = new SplashState(bitmap->width, bitmap->height);
47 softMask = NULL;
48 clearModRegion();
49 debugMode = gFalse;
50 }
51
52 Splash::~Splash() {
53 while (state->next) {
54 restoreState();
55 }
56 delete state;
57 if (softMask) {
58 delete softMask;
59 }
60 }
61
62 //------------------------------------------------------------------------
63 // state read
64 //------------------------------------------------------------------------
65
66 SplashPattern *Splash::getStrokePattern() {
67 return state->strokePattern;
68 }
69
70 SplashPattern *Splash::getFillPattern() {
71 return state->fillPattern;
72 }
73
74 SplashScreen *Splash::getScreen() {
75 return state->screen;
76 }
77
78 SplashBlendFunc Splash::getBlendFunc() {
79 return state->blendFunc;
80 }
81
82 SplashCoord Splash::getStrokeAlpha() {
83 return state->strokeAlpha;
84 }
85
86 SplashCoord Splash::getFillAlpha() {
87 return state->fillAlpha;
88 }
89
90 SplashCoord Splash::getLineWidth() {
91 return state->lineWidth;
92 }
93
94 int Splash::getLineCap() {
95 return state->lineCap;
96 }
97
98 int Splash::getLineJoin() {
99 return state->lineJoin;
100 }
101
102 SplashCoord Splash::getMiterLimit() {
103 return state->miterLimit;
104 }
105
106 SplashCoord Splash::getFlatness() {
107 return state->flatness;
108 }
109
110 SplashCoord *Splash::getLineDash() {
111 return state->lineDash;
112 }
113
114 int Splash::getLineDashLength() {
115 return state->lineDashLength;
116 }
117
118 SplashCoord Splash::getLineDashPhase() {
119 return state->lineDashPhase;
120 }
121
122 SplashClip *Splash::getClip() {
123 return state->clip;
124 }
125
126 //------------------------------------------------------------------------
127 // state write
128 //------------------------------------------------------------------------
129
130 void Splash::setStrokePattern(SplashPattern *strokePattern) {
131 state->setStrokePattern(strokePattern);
132 }
133
134 void Splash::setFillPattern(SplashPattern *fillPattern) {
135 state->setFillPattern(fillPattern);
136 }
137
138 void Splash::setScreen(SplashScreen *screen) {
139 state->setScreen(screen);
140 }
141
142 void Splash::setBlendFunc(SplashBlendFunc func) {
143 state->blendFunc = func;
144 }
145
146 void Splash::setStrokeAlpha(SplashCoord alpha) {
147 state->strokeAlpha = alpha;
148 }
149
150 void Splash::setFillAlpha(SplashCoord alpha) {
151 state->fillAlpha = alpha;
152 }
153
154 void Splash::setLineWidth(SplashCoord lineWidth) {
155 state->lineWidth = lineWidth;
156 }
157
158 void Splash::setLineCap(int lineCap) {
159 state->lineCap = lineCap;
160 }
161
162 void Splash::setLineJoin(int lineJoin) {
163 state->lineJoin = lineJoin;
164 }
165
166 void Splash::setMiterLimit(SplashCoord miterLimit) {
167 state->miterLimit = miterLimit;
168 }
169
170 void Splash::setFlatness(SplashCoord flatness) {
171 if (flatness < 1) {
172 state->flatness = 1;
173 } else {
174 state->flatness = flatness;
175 }
176 }
177
178 void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
179 SplashCoord lineDashPhase) {
180 state->setLineDash(lineDash, lineDashLength, lineDashPhase);
181 }
182
183 void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
184 SplashCoord x1, SplashCoord y1) {
185 state->clip->resetToRect(x0, y0, x1, y1);
186 }
187
188 SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
189 SplashCoord x1, SplashCoord y1) {
190 return state->clip->clipToRect(x0, y0, x1, y1);
191 }
192
193 SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
194 return state->clip->clipToPath(path, state->flatness, eo);
195 }
196
197 //------------------------------------------------------------------------
198 // state save/restore
199 //------------------------------------------------------------------------
200
201 void Splash::saveState() {
202 SplashState *newState;
203
204 newState = state->copy();
205 newState->next = state;
206 state = newState;
207 }
208
209 SplashError Splash::restoreState() {
210 SplashState *oldState;
211
212 if (!state->next) {
213 return splashErrNoSave;
214 }
215 oldState = state;
216 state = state->next;
217 delete oldState;
218 return splashOk;
219 }
220
221 //------------------------------------------------------------------------
222 // soft mask
223 //------------------------------------------------------------------------
224
225 void Splash::setSoftMask(SplashBitmap *softMaskA) {
226 if (softMask) {
227 delete softMask;
228 }
229 softMask = softMaskA;
230 }
231
232 //------------------------------------------------------------------------
233 // modified region
234 //------------------------------------------------------------------------
235
236 void Splash::clearModRegion() {
237 modXMin = bitmap->getWidth();
238 modYMin = bitmap->getHeight();
239 modXMax = -1;
240 modYMax = -1;
241 }
242
243 inline void Splash::updateModX(int x) {
244 if (x < modXMin) {
245 modXMin = x;
246 }
247 if (x > modXMax) {
248 modXMax = x;
249 }
250 }
251
252 inline void Splash::updateModY(int y) {
253 if (y < modYMin) {
254 modYMin = y;
255 }
256 if (y > modYMax) {
257 modYMax = y;
258 }
259 }
260
261 //------------------------------------------------------------------------
262 // drawing operations
263 //------------------------------------------------------------------------
264
265 void Splash::clear(SplashColorPtr color) {
266 SplashColorPtr row, p;
267 Guchar mono;
268 int x, y;
269
270 switch (bitmap->mode) {
271 case splashModeMono1:
272 mono = color[0] ? 0xff : 0x00;
273 if (bitmap->rowSize < 0) {
274 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
275 mono, -bitmap->rowSize * bitmap->height);
276 } else {
277 memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
278 }
279 break;
280 case splashModeMono8:
281 if (bitmap->rowSize < 0) {
282 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
283 color[0], -bitmap->rowSize * bitmap->height);
284 } else {
285 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
286 }
287 break;
288 case splashModeAMono8:
289 if (color[0] == color[1]) {
290 if (bitmap->rowSize < 0) {
291 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
292 color[0], -bitmap->rowSize * bitmap->height);
293 } else {
294 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
295 }
296 } else {
297 row = bitmap->data;
298 for (y = 0; y < bitmap->height; ++y) {
299 p = row;
300 for (x = 0; x < bitmap->width; ++x) {
301 *p++ = color[0];
302 *p++ = color[1];
303 }
304 row += bitmap->rowSize;
305 }
306 }
307 break;
308 case splashModeRGB8:
309 case splashModeBGR8:
310 if (color[0] == color[1] && color[1] == color[2]) {
311 if (bitmap->rowSize < 0) {
312 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
313 color[0], -bitmap->rowSize * bitmap->height);
314 } else {
315 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
316 }
317 } else {
318 row = bitmap->data;
319 for (y = 0; y < bitmap->height; ++y) {
320 p = row;
321 for (x = 0; x < bitmap->width; ++x) {
322 *p++ = color[0];
323 *p++ = color[1];
324 *p++ = color[2];
325 }
326 row += bitmap->rowSize;
327 }
328 }
329 break;
330 case splashModeARGB8:
331 case splashModeBGRA8:
332 #if SPLASH_CMYK
333 case splashModeCMYK8:
334 #endif
335 if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
336 if (bitmap->rowSize < 0) {
337 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
338 color[0], -bitmap->rowSize * bitmap->height);
339 } else {
340 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
341 }
342 } else {
343 row = bitmap->data;
344 for (y = 0; y < bitmap->height; ++y) {
345 p = row;
346 for (x = 0; x < bitmap->width; ++x) {
347 *p++ = color[0];
348 *p++ = color[1];
349 *p++ = color[2];
350 *p++ = color[3];
351 }
352 row += bitmap->rowSize;
353 }
354 }
355 break;
356 #if SPLASH_CMYK
357 case splashModeACMYK8:
358 if (color[0] == color[1] && color[1] == color[2] &&
359 color[2] == color[3] && color[3] == color[4]) {
360 if (bitmap->rowSize < 0) {
361 memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
362 color[0], -bitmap->rowSize * bitmap->height);
363 } else {
364 memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
365 }
366 } else {
367 row = bitmap->data;
368 for (y = 0; y < bitmap->height; ++y) {
369 p = row;
370 for (x = 0; x < bitmap->width; ++x) {
371 *p++ = color[0];
372 *p++ = color[1];
373 *p++ = color[2];
374 *p++ = color[3];
375 *p++ = color[4];
376 }
377 row += bitmap->rowSize;
378 }
379 }
380 break;
381 #endif
382 }
383
384 updateModX(0);
385 updateModY(0);
386 updateModX(bitmap->width - 1);
387 updateModY(bitmap->height - 1);
388 }
389
390 SplashError Splash::stroke(SplashPath *path) {
391 SplashXPath *xPath, *xPath2;
392
393 if (debugMode) {
394 printf("stroke [dash:%d] [width:%.2f]:\n",
395 state->lineDashLength, (double)state->lineWidth);
396 dumpPath(path);
397 }
398 opClipRes = splashClipAllOutside;
399 if (path->length == 0) {
400 return splashErrEmptyPath;
401 }
402 xPath = new SplashXPath(path, state->flatness, gFalse);
403 if (xPath->length == 0) {
404 delete xPath;
405 return splashErrEmptyPath;
406 }
407 if (state->lineDashLength > 0) {
408 xPath2 = makeDashedPath(xPath);
409 delete xPath;
410 xPath = xPath2;
411 }
412 if (state->lineWidth <= 1) {
413 strokeNarrow(xPath);
414 } else {
415 strokeWide(xPath);
416 }
417 delete xPath;
418 return splashOk;
419 }
420
421 void Splash::strokeNarrow(SplashXPath *xPath) {
422 SplashXPathSeg *seg;
423 int x0, x1, x2, x3, y0, y1, x, y, t;
424 SplashCoord dx, dy, dxdy;
425 SplashClipResult clipRes;
426 int nClipRes[3];
427 int i;
428
429 for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
430
431 x0 = splashFloor(seg->x0);
432 x1 = splashFloor(seg->x1);
433 y0 = splashFloor(seg->y0);
434 y1 = splashFloor(seg->y1);
435
436 // horizontal segment
437 if (y0 == y1) {
438 if (x0 > x1) {
439 t = x0; x0 = x1; x1 = t;
440 }
441 if ((clipRes = state->clip->testSpan(x0, x1, y0))
442 != splashClipAllOutside) {
443 drawSpan(x0, x1, y0, state->strokePattern, state->strokeAlpha,
444 clipRes == splashClipAllInside);
445 }
446
447 // segment with |dx| > |dy|
448 } else if (splashAbs(seg->dxdy) > 1) {
449 dx = seg->x1 - seg->x0;
450 dy = seg->y1 - seg->y0;
451 dxdy = seg->dxdy;
452 if (y0 > y1) {
453 t = y0; y0 = y1; y1 = t;
454 t = x0; x0 = x1; x1 = t;
455 dx = -dx;
456 dy = -dy;
457 }
458 if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
459 x0 <= x1 ? x1 : x0, y1))
460 != splashClipAllOutside) {
461 if (dx > 0) {
462 x2 = x0;
463 x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
464 drawSpan(x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, state->strokePattern,
465 state->strokeAlpha, clipRes == splashClipAllInside);
466 x2 = x3;
467 for (y = y0 + 1; y <= y1 - 1; ++y) {
468 x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
469 drawSpan(x2, x3 - 1, y, state->strokePattern,
470 state->strokeAlpha, clipRes == splashClipAllInside);
471 x2 = x3;
472 }
473 drawSpan(x2, x2 <= x1 ? x1 : x2, y1, state->strokePattern,
474 state->strokeAlpha, clipRes == splashClipAllInside);
475 } else {
476 x2 = x0;
477 x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
478 drawSpan((x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, state->strokePattern,
479 state->strokeAlpha, clipRes == splashClipAllInside);
480 x2 = x3;
481 for (y = y0 + 1; y <= y1 - 1; ++y) {
482 x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
483 drawSpan(x3 + 1, x2, y, state->strokePattern,
484 state->strokeAlpha, clipRes == splashClipAllInside);
485 x2 = x3;
486 }
487 drawSpan(x1, (x1 <= x2) ? x2 : x1, y1, state->strokePattern,
488 state->strokeAlpha, clipRes == splashClipAllInside);
489 }
490 }
491
492 // segment with |dy| > |dx|
493 } else {
494 dxdy = seg->dxdy;
495 if (y0 > y1) {
496 t = x0; x0 = x1; x1 = t;
497 t = y0; y0 = y1; y1 = t;
498 }
499 if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
500 x0 <= x1 ? x1 : x0, y1))
501 != splashClipAllOutside) {
502 drawPixel(x0, y0, state->strokePattern, state->strokeAlpha,
503 clipRes == splashClipAllInside);
504 for (y = y0 + 1; y <= y1 - 1; ++y) {
505 x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
506 drawPixel(x, y, state->strokePattern, state->strokeAlpha,
507 clipRes == splashClipAllInside);
508 }
509 drawPixel(x1, y1, state->strokePattern, state->strokeAlpha,
510 clipRes == splashClipAllInside);
511 }
512 }
513 ++nClipRes[clipRes];
514 }
515 if (nClipRes[splashClipPartial] ||
516 (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
517 opClipRes = splashClipPartial;
518 } else if (nClipRes[splashClipAllInside]) {
519 opClipRes = splashClipAllInside;
520 } else {
521 opClipRes = splashClipAllOutside;
522 }
523 }
524
525 void Splash::strokeWide(SplashXPath *xPath) {
526 SplashXPathSeg *seg, *seg2;
527 SplashPath *widePath;
528 SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev;
529 SplashCoord dotprod, miter;
530 int i, j;
531
532 dx = dy = wdx = wdy = 0; // make gcc happy
533 dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy
534
535 for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
536
537 // save the deltas for the previous segment; if this is the first
538 // segment on a subpath, compute the deltas for the last segment
539 // on the subpath (which may be used to draw a line join)
540 if (seg->flags & splashXPathFirst) {
541 for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) {
542 if (seg2->flags & splashXPathLast) {
543 d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1);
544 if (d == 0) {
545 //~ not clear what the behavior should be for joins with d==0
546 dxPrev = 0;
547 dyPrev = 1;
548 } else {
549 d = (SplashCoord)1 / d;
550 dxPrev = d * (seg2->x1 - seg2->x0);
551 dyPrev = d * (seg2->y1 - seg2->y0);
552 }
553 wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev;
554 wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev;
555 break;
556 }
557 }
558 } else {
559 dxPrev = dx;
560 dyPrev = dy;
561 wdxPrev = wdx;
562 wdyPrev = wdy;
563 }
564
565 // compute deltas for this line segment
566 d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1);
567 if (d == 0) {
568 // we need to draw end caps on zero-length lines
569 //~ not clear what the behavior should be for splashLineCapButt with d==0
570 dx = 0;
571 dy = 1;
572 } else {
573 d = (SplashCoord)1 / d;
574 dx = d * (seg->x1 - seg->x0);
575 dy = d * (seg->y1 - seg->y0);
576 }
577 wdx = (SplashCoord)0.5 * state->lineWidth * dx;
578 wdy = (SplashCoord)0.5 * state->lineWidth * dy;
579
580 // initialize the path (which will be filled)
581 widePath = new SplashPath();
582 widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx);
583
584 // draw the start cap
585 if (seg->flags & splashXPathEnd0) {
586 switch (state->lineCap) {
587 case splashLineCapButt:
588 widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
589 break;
590 case splashLineCapRound:
591 widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0);
592 break;
593 case splashLineCapProjecting:
594 widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy);
595 widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy);
596 widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
597 break;
598 }
599 } else {
600 widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
601 }
602
603 // draw the left side of the segment
604 widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx);
605
606 // draw the end cap
607 if (seg->flags & splashXPathEnd1) {
608 switch (state->lineCap) {
609 case splashLineCapButt:
610 widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
611 break;
612 case splashLineCapRound:
613 widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1);
614 break;
615 case splashLineCapProjecting:
616 widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy);
617 widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy);
618 widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
619 break;
620 }
621 } else {
622 widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
623 }
624
625 // draw the right side of the segment
626 widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
627
628 // fill the segment
629 fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha);
630 delete widePath;
631
632 // draw the line join
633 if (!(seg->flags & splashXPathEnd0)) {
634 widePath = NULL;
635 switch (state->lineJoin) {
636 case splashLineJoinMiter:
637 dotprod = -(dx * dxPrev + dy * dyPrev);
638 if (splashAbs(splashAbs(dotprod) - 1) > 0.01) {
639 widePath = new SplashPath();
640 widePath->moveTo(seg->x0, seg->y0);
641 miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
642 if (splashSqrt(miter) <= state->miterLimit) {
643 miter = splashSqrt(miter - 1);
644 if (dy * dxPrev > dx * dyPrev) {
645 widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
646 widePath->lineTo(seg->x0 + wdy - miter * wdx,
647 seg->y0 - wdx - miter * wdy);
648 widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
649 } else {
650 widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
651 widePath->lineTo(seg->x0 - wdy - miter * wdx,
652 seg->y0 + wdx - miter * wdy);
653 widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
654 }
655 } else {
656 if (dy * dxPrev > dx * dyPrev) {
657 widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
658 widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
659 } else {
660 widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
661 widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
662 }
663 }
664 }
665 break;
666 case splashLineJoinRound:
667 widePath = new SplashPath();
668 widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx);
669 widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0);
670 break;
671 case splashLineJoinBevel:
672 widePath = new SplashPath();
673 widePath->moveTo(seg->x0, seg->y0);
674 if (dy * dxPrev > dx * dyPrev) {
675 widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
676 widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
677 } else {
678 widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
679 widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
680 }
681 break;
682 }
683 if (widePath) {
684 fillWithPattern(widePath, gTrue, state->strokePattern,
685 state->strokeAlpha);
686 delete widePath;
687 }
688 }
689 }
690 }
691
692 SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) {
693 SplashXPath *dPath;
694 GBool lineDashStartOn, lineDashOn;
695 GBool atSegStart, atSegEnd, atDashStart, atDashEnd;
696 int lineDashStartIdx, lineDashIdx, subpathStart;
697 SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist;
698 int segIdx;
699 SplashXPathSeg *seg;
700 SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist;
701 int i;
702
703 dPath = new SplashXPath();
704
705 lineDashTotal = 0;
706 for (i = 0; i < state->lineDashLength; ++i) {
707 lineDashTotal += state->lineDash[i];
708 }
709 lineDashStartPhase = state->lineDashPhase;
710 i = splashFloor(lineDashStartPhase / lineDashTotal);
711 lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
712 lineDashStartOn = gTrue;
713 lineDashStartIdx = 0;
714 while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
715 lineDashStartOn = !lineDashStartOn;
716 lineDashStartPhase -= state->lineDash[lineDashStartIdx];
717 ++lineDashStartIdx;
718 }
719
720 segIdx = 0;
721 seg = xPath->segs;
722 sx0 = seg->x0;
723 sy0 = seg->y0;
724 sx1 = seg->x1;
725 sy1 = seg->y1;
726 dist = splashDist(sx0, sy0, sx1, sy1);
727 lineDashOn = lineDashStartOn;
728 lineDashIdx = lineDashStartIdx;
729 lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
730 atSegStart = gTrue;
731 atDashStart = gTrue;
732 subpathStart = dPath->length;
733
734 while (segIdx < xPath->length) {
735
736 ax0 = sx0;
737 ay0 = sy0;
738 if (dist <= lineDashDist) {
739 ax1 = sx1;
740 ay1 = sy1;
741 lineDashDist -= dist;
742 dist = 0;
743 atSegEnd = gTrue;
744 atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast);
745 } else {
746 ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0);
747 ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0);
748 sx0 = ax1;
749 sy0 = ay1;
750 dist -= lineDashDist;
751 lineDashDist = 0;
752 atSegEnd = gFalse;
753 atDashEnd = gTrue;
754 }
755
756 if (lineDashOn) {
757 dPath->addSegment(ax0, ay0, ax1, ay1,
758 atDashStart, atDashEnd,
759 atDashStart, atDashEnd);
760 // end of closed subpath
761 if (atSegEnd &&
762 (seg->flags & splashXPathLast) &&
763 !(seg->flags & splashXPathEnd1)) {
764 dPath->segs[subpathStart].flags &= ~splashXPathEnd0;
765 dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1;
766 }
767 }
768
769 if (atDashEnd) {
770 lineDashOn = !lineDashOn;
771 if (++lineDashIdx == state->lineDashLength) {
772 lineDashIdx = 0;
773 }
774 lineDashDist = state->lineDash[lineDashIdx];
775 atDashStart = gTrue;
776 } else {
777 atDashStart = gFalse;
778 }
779 if (atSegEnd) {
780 if (++segIdx < xPath->length) {
781 ++seg;
782 sx0 = seg->x0;
783 sy0 = seg->y0;
784 sx1 = seg->x1;
785 sy1 = seg->y1;
786 dist = splashDist(sx0, sy0, sx1, sy1);
787 if (seg->flags & splashXPathFirst) {
788 lineDashOn = lineDashStartOn;
789 lineDashIdx = lineDashStartIdx;
790 lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
791 atDashStart = gTrue;
792 subpathStart = dPath->length;
793 }
794 }
795 atSegStart = gTrue;
796 } else {
797 atSegStart = gFalse;
798 }
799 }
800
801 return dPath;
802 }
803
804 SplashError Splash::fill(SplashPath *path, GBool eo) {
805 if (debugMode) {
806 printf("fill [eo:%d]:\n", eo);
807 dumpPath(path);
808 }
809 return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
810 }
811
812 SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
813 SplashPattern *pattern,
814 SplashCoord alpha) {
815 SplashXPath *xPath;
816 SplashXPathScanner *scanner;
817 int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
818 SplashClipResult clipRes, clipRes2;
819
820 if (path->length == 0) {
821 return splashErrEmptyPath;
822 }
823 xPath = new SplashXPath(path, state->flatness, gTrue);
824 xPath->sort();
825 scanner = new SplashXPathScanner(xPath, eo);
826
827 // get the min and max x and y values
828 scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
829
830 // check clipping
831 if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
832 != splashClipAllOutside) {
833
834 // limit the y range
835 if (yMinI < state->clip->getYMin()) {
836 yMinI = state->clip->getYMin();
837 }
838 if (yMaxI > state->clip->getYMax()) {
839 yMaxI = state->clip->getYMax();
840 }
841
842 // draw the spans
843 for (y = yMinI; y <= yMaxI; ++y) {
844 while (scanner->getNextSpan(y, &x0, &x1)) {
845 if (clipRes == splashClipAllInside) {
846 drawSpan(x0, x1, y, pattern, alpha, gTrue);
847 } else {
848 // limit the x range
849 if (x0 < state->clip->getXMin()) {
850 x0 = state->clip->getXMin();
851 }
852 if (x1 > state->clip->getXMax()) {
853 x1 = state->clip->getXMax();
854 }
855 clipRes2 = state->clip->testSpan(x0, x1, y);
856 drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside);
857 }
858 }
859 }
860 }
861 opClipRes = clipRes;
862
863 delete scanner;
864 delete xPath;
865 return splashOk;
866 }
867
868 SplashError Splash::xorFill(SplashPath *path, GBool eo) {
869 SplashXPath *xPath;
870 SplashXPathScanner *scanner;
871 int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
872 SplashClipResult clipRes, clipRes2;
873
874 if (path->length == 0) {
875 return splashErrEmptyPath;
876 }
877 xPath = new SplashXPath(path, state->flatness, gTrue);
878 xPath->sort();
879 scanner = new SplashXPathScanner(xPath, eo);
880
881 // get the min and max x and y values
882 scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
883
884 // check clipping
885 if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
886 != splashClipAllOutside) {
887
888 // limit the y range
889 if (yMinI < state->clip->getYMin()) {
890 yMinI = state->clip->getYMin();
891 }
892 if (yMaxI > state->clip->getYMax()) {
893 yMaxI = state->clip->getYMax();
894 }
895
896 // draw the spans
897 for (y = yMinI; y <= yMaxI; ++y) {
898 while (scanner->getNextSpan(y, &x0, &x1)) {
899 if (clipRes == splashClipAllInside) {
900 xorSpan(x0, x1, y, state->fillPattern, gTrue);
901 } else {
902 // limit the x range
903 if (x0 < state->clip->getXMin()) {
904 x0 = state->clip->getXMin();
905 }
906 if (x1 > state->clip->getXMax()) {
907 x1 = state->clip->getXMax();
908 }
909 clipRes2 = state->clip->testSpan(x0, x1, y);
910 xorSpan(x0, x1, y, state->fillPattern,
911 clipRes2 == splashClipAllInside);
912 }
913 }
914 }
915 }
916 opClipRes = clipRes;
917
918 delete scanner;
919 delete xPath;
920 return splashOk;
921 }
922
923 void Splash::drawPixel(int x, int y, SplashColorPtr color,
924 SplashCoord alpha, GBool noClip) {
925 SplashBlendFunc blendFunc;
926 SplashColorPtr p;
927 SplashColor dest, blend;
928 int alpha2, ialpha2;
929 Guchar t;
930
931 if (noClip || state->clip->test(x, y)) {
932 if (alpha != 1 || softMask || state->blendFunc) {
933 blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
934 if (softMask) {
935 alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]);
936 } else {
937 alpha2 = (int)(alpha * 255);
938 }
939 ialpha2 = 255 - alpha2;
940 switch (bitmap->mode) {
941 case splashModeMono1:
942 p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
943 dest[0] = (*p >> (7 - (x & 7))) & 1;
944 (*blendFunc)(color, dest, blend, bitmap->mode);
945 t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
946 if (t) {
947 *p |= 0x80 >> (x & 7);
948 } else {
949 *p &= ~(0x80 >> (x & 7));
950 }
951 break;
952 case splashModeMono8:
953 p = &bitmap->data[y * bitmap->rowSize + x];
954 (*blendFunc)(color, p, blend, bitmap->mode);
955 // note: floor(x / 255) = x >> 8 (for 16-bit x)
956 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
957 break;
958 case splashModeAMono8:
959 p = &bitmap->data[y * bitmap->rowSize + 2 * x];
960 (*blendFunc)(color, p, blend, bitmap->mode);
961 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
962 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
963 break;
964 case splashModeRGB8:
965 case splashModeBGR8:
966 p = &bitmap->data[y * bitmap->rowSize + 3 * x];
967 (*blendFunc)(color, p, blend, bitmap->mode);
968 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
969 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
970 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
971 break;
972 case splashModeARGB8:
973 case splashModeBGRA8:
974 #if SPLASH_CMYK
975 case splashModeCMYK8:
976 #endif
977 p = &bitmap->data[y * bitmap->rowSize + 4 * x];
978 (*blendFunc)(color, p, blend, bitmap->mode);
979 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
980 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
981 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
982 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
983 break;
984 #if SPLASH_CMYK
985 case splashModeACMYK8:
986 p = &bitmap->data[y * bitmap->rowSize + 5 * x];
987 (*blendFunc)(color, p, blend, bitmap->mode);
988 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
989 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
990 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
991 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
992 p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
993 break;
994 #endif
995 }
996 } else {
997 switch (bitmap->mode) {
998 case splashModeMono1:
999 p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
1000 if (color[0]) {
1001 *p |= 0x80 >> (x & 7);
1002 } else {
1003 *p &= ~(0x80 >> (x & 7));
1004 }
1005 break;
1006 case splashModeMono8:
1007 p = &bitmap->data[y * bitmap->rowSize + x];
1008 p[0] = color[0];
1009 break;
1010 case splashModeAMono8:
1011 p = &bitmap->data[y * bitmap->rowSize + 2 * x];
1012 p[0] = color[0];
1013 p[1] = color[1];
1014 break;
1015 case splashModeRGB8:
1016 case splashModeBGR8:
1017 p = &bitmap->data[y * bitmap->rowSize + 3 * x];
1018 p[0] = color[0];
1019 p[1] = color[1];
1020 p[2] = color[2];
1021 break;
1022 case splashModeARGB8:
1023 case splashModeBGRA8:
1024 #if SPLASH_CMYK
1025 case splashModeCMYK8:
1026 #endif
1027 p = &bitmap->data[y * bitmap->rowSize + 4 * x];
1028 p[0] = color[0];
1029 p[1] = color[1];
1030 p[2] = color[2];
1031 p[3] = color[3];
1032 break;
1033 #if SPLASH_CMYK
1034 case splashModeACMYK8:
1035 p = &bitmap->data[y * bitmap->rowSize + 5 * x];
1036 p[0] = color[0];
1037 p[1] = color[1];
1038 p[2] = color[2];
1039 p[3] = color[3];
1040 p[4] = color[4];
1041 break;
1042 #endif
1043 }
1044 }
1045 updateModX(x);
1046 updateModY(y);
1047 }
1048 }
1049
1050 void Splash::drawPixel(int x, int y, SplashPattern *pattern,
1051 SplashCoord alpha, GBool noClip) {
1052 SplashBlendFunc blendFunc;
1053 SplashColor color;
1054 SplashColorPtr p;
1055 SplashColor dest, blend;
1056 int alpha2, ialpha2;
1057 Guchar t;
1058
1059 if (noClip || state->clip->test(x, y)) {
1060 if (alpha != 1 || softMask || state->blendFunc) {
1061 blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
1062 pattern->getColor(x, y, color);
1063 if (softMask) {
1064 alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]);
1065 } else {
1066 alpha2 = (int)(alpha * 255);
1067 }
1068 ialpha2 = 255 - alpha2;
1069 switch (bitmap->mode) {
1070 case splashModeMono1:
1071 p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
1072 dest[0] = (*p >> (7 - (x & 7))) & 1;
1073 (*blendFunc)(color, dest, blend, bitmap->mode);
1074 t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1075 if (t) {
1076 *p |= 0x80 >> (x & 7);
1077 } else {
1078 *p &= ~(0x80 >> (x & 7));
1079 }
1080 break;
1081 case splashModeMono8:
1082 p = &bitmap->data[y * bitmap->rowSize + x];
1083 (*blendFunc)(color, p, blend, bitmap->mode);
1084 // note: floor(x / 255) = x >> 8 (for 16-bit x)
1085 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1086 break;
1087 case splashModeAMono8:
1088 p = &bitmap->data[y * bitmap->rowSize + 2 * x];
1089 (*blendFunc)(color, p, blend, bitmap->mode);
1090 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1091 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1092 break;
1093 case splashModeRGB8:
1094 case splashModeBGR8:
1095 p = &bitmap->data[y * bitmap->rowSize + 3 * x];
1096 (*blendFunc)(color, p, blend, bitmap->mode);
1097 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1098 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1099 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1100 break;
1101 case splashModeARGB8:
1102 case splashModeBGRA8:
1103 #if SPLASH_CMYK
1104 case splashModeCMYK8:
1105 #endif
1106 p = &bitmap->data[y * bitmap->rowSize + 4 * x];
1107 (*blendFunc)(color, p, blend, bitmap->mode);
1108 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1109 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1110 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1111 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1112 break;
1113 #if SPLASH_CMYK
1114 case splashModeACMYK8:
1115 p = &bitmap->data[y * bitmap->rowSize + 5 * x];
1116 (*blendFunc)(color, p, blend, bitmap->mode);
1117 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1118 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1119 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1120 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1121 p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
1122 break;
1123 #endif
1124 }
1125 } else {
1126 pattern->getColor(x, y, color);
1127 switch (bitmap->mode) {
1128 case splashModeMono1:
1129 p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
1130 if (color[0]) {
1131 *p |= 0x80 >> (x & 7);
1132 } else {
1133 *p &= ~(0x80 >> (x & 7));
1134 }
1135 break;
1136 case splashModeMono8:
1137 p = &bitmap->data[y * bitmap->rowSize + x];
1138 p[0] = color[0];
1139 break;
1140 case splashModeAMono8:
1141 p = &bitmap->data[y * bitmap->rowSize + 2 * x];
1142 p[0] = color[0];
1143 p[1] = color[1];
1144 break;
1145 case splashModeRGB8:
1146 case splashModeBGR8:
1147 p = &bitmap->data[y * bitmap->rowSize + 3 * x];
1148 p[0] = color[0];
1149 p[1] = color[1];
1150 p[2] = color[2];
1151 break;
1152 case splashModeARGB8:
1153 case splashModeBGRA8:
1154 #if SPLASH_CMYK
1155 case splashModeCMYK8:
1156 #endif
1157 p = &bitmap->data[y * bitmap->rowSize + 4 * x];
1158 p[0] = color[0];
1159 p[1] = color[1];
1160 p[2] = color[2];
1161 p[3] = color[3];
1162 break;
1163 #if SPLASH_CMYK
1164 case splashModeACMYK8:
1165 p = &bitmap->data[y * bitmap->rowSize + 5 * x];
1166 p[0] = color[0];
1167 p[1] = color[1];
1168 p[2] = color[2];
1169 p[3] = color[3];
1170 p[4] = color[4];
1171 break;
1172 #endif
1173 }
1174 }
1175 updateModX(x);
1176 updateModY(y);
1177 }
1178 }
1179
1180 void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern,
1181 SplashCoord alpha, GBool noClip) {
1182 SplashBlendFunc blendFunc;
1183 SplashColor color;
1184 SplashColorPtr p;
1185 SplashColor dest, blend;
1186 Guchar mask, t;
1187 int alpha2, ialpha2;
1188 int i, j, n;
1189
1190 n = x1 - x0 + 1;
1191
1192 if (noClip) {
1193 updateModX(x0);
1194 updateModX(x1);
1195 updateModY(y);
1196 }
1197
1198 if (alpha != 1 || softMask || state->blendFunc) {
1199 blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
1200 if (softMask) {
1201 alpha2 = ialpha2 = 0; // make gcc happy
1202 } else {
1203 alpha2 = (int)(alpha * 255);
1204 ialpha2 = 255 - alpha2;
1205 }
1206 switch (bitmap->mode) {
1207 case splashModeMono1:
1208 p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1209 i = 0;
1210 if (pattern->isStatic()) {
1211 pattern->getColor(0, 0, color);
1212 if ((j = x0 & 7)) {
1213 mask = 0x80 >> j;
1214 for (; j < 8 && i < n; ++i, ++j) {
1215 if (noClip || state->clip->test(x0 + i, y)) {
1216 if (softMask) {
1217 alpha2 = (int)(alpha *
1218 softMask->data[y * softMask->rowSize + x0 + i]);
1219 ialpha2 = 255 - alpha2;
1220 }
1221 dest[0] = (*p >> (7 - j)) & 1;
1222 (*blendFunc)(color, dest, blend, bitmap->mode);
1223 t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1224 if (t) {
1225 *p |= mask;
1226 } else {
1227 *p &= ~mask;
1228 }
1229 if (!noClip) {
1230 updateModX(x0 + i);
1231 updateModY(y);
1232 }
1233 }
1234 mask >>= 1;
1235 }
1236 ++p;
1237 }
1238 while (i < n) {
1239 mask = 0x80;
1240 for (j = 0; j < 8 && i < n; ++i, ++j) {
1241 if (noClip || state->clip->test(x0 + i, y)) {
1242 if (softMask) {
1243 alpha2 = (int)(alpha *
1244 softMask->data[y * softMask->rowSize + x0 + i]);
1245 ialpha2 = 255 - alpha2;
1246 }
1247 dest[0] = (*p >> (7 - j)) & 1;
1248 (*blendFunc)(color, dest, blend, bitmap->mode);
1249 t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1250 if (t) {
1251 *p |= mask;
1252 } else {
1253 *p &= ~mask;
1254 }
1255 if (!noClip) {
1256 updateModX(x0 + i);
1257 updateModY(y);
1258 }
1259 }
1260 mask >>= 1;
1261 }
1262 ++p;
1263 }
1264 } else {
1265 if ((j = x0 & 7)) {
1266 mask = 0x80 >> j;
1267 for (; j < 8 && i < n; ++i, ++j) {
1268 if (noClip || state->clip->test(x0 + i, y)) {
1269 pattern->getColor(x0 + i, y, color);
1270 if (softMask) {
1271 alpha2 = (int)(alpha *
1272 softMask->data[y * softMask->rowSize + x0 + i]);
1273 ialpha2 = 255 - alpha2;
1274 }
1275 dest[0] = (*p >> (7 - j)) & 1;
1276 (*blendFunc)(color, dest, blend, bitmap->mode);
1277 t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1278 if (t) {
1279 *p |= mask;
1280 } else {
1281 *p &= ~mask;
1282 }
1283 if (!noClip) {
1284 updateModX(x0 + i);
1285 updateModY(y);
1286 }
1287 }
1288 mask >>= 1;
1289 }
1290 ++p;
1291 }
1292 while (i < n) {
1293 mask = 0x80;
1294 for (j = 0; j < 8 && i < n; ++i, ++j) {
1295 if (noClip || state->clip->test(x0 + i, y)) {
1296 pattern->getColor(x0 + i, y, color);
1297 if (softMask) {
1298 alpha2 = (int)(alpha *
1299 softMask->data[y * softMask->rowSize + x0 + i]);
1300 ialpha2 = 255 - alpha2;
1301 }
1302 dest[0] = (*p >> (7 - j)) & 1;
1303 (*blendFunc)(color, dest, blend, bitmap->mode);
1304 t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1305 if (t) {
1306 *p |= mask;
1307 } else {
1308 *p &= ~mask;
1309 }
1310 if (!noClip) {
1311 updateModX(x0 + i);
1312 updateModY(y);
1313 }
1314 }
1315 mask >>= 1;
1316 }
1317 ++p;
1318 }
1319 }
1320 break;
1321
1322 case splashModeMono8:
1323 p = &bitmap->data[y * bitmap->rowSize + x0];
1324 if (pattern->isStatic()) {
1325 pattern->getColor(0, 0, color);
1326 for (i = 0; i < n; ++i) {
1327 if (noClip || state->clip->test(x0 + i, y)) {
1328 if (softMask) {
1329 alpha2 = (int)(alpha *
1330 softMask->data[y * softMask->rowSize + x0 + i]);
1331 ialpha2 = 255 - alpha2;
1332 }
1333 (*blendFunc)(color, p, blend, bitmap->mode);
1334 *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8;
1335 if (!noClip) {
1336 updateModX(x0 + i);
1337 updateModY(y);
1338 }
1339 }
1340 ++p;
1341 }
1342 } else {
1343 for (i = 0; i < n; ++i) {
1344 if (noClip || state->clip->test(x0 + i, y)) {
1345 pattern->getColor(x0 + i, y, color);
1346 if (softMask) {
1347 alpha2 = (int)(alpha *
1348 softMask->data[y * softMask->rowSize + x0 + i]);
1349 ialpha2 = 255 - alpha2;
1350 }
1351 (*blendFunc)(color, p, blend, bitmap->mode);
1352 *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8;
1353 if (!noClip) {
1354 updateModX(x0 + i);
1355 updateModY(y);
1356 }
1357 }
1358 ++p;
1359 }
1360 }
1361 break;
1362
1363 case splashModeAMono8:
1364 p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
1365 if (pattern->isStatic()) {
1366 pattern->getColor(0, 0, color);
1367 for (i = 0; i < n; ++i) {
1368 if (noClip || state->clip->test(x0 + i, y)) {
1369 if (softMask) {
1370 alpha2 = (int)(alpha *
1371 softMask->data[y * softMask->rowSize + x0 + i]);
1372 ialpha2 = 255 - alpha2;
1373 }
1374 (*blendFunc)(color, p, blend, bitmap->mode);
1375 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1376 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1377 if (!noClip) {
1378 updateModX(x0 + i);
1379 updateModY(y);
1380 }
1381 }
1382 p += 2;
1383 }
1384 } else {
1385 for (i = 0; i < n; ++i) {
1386 if (noClip || state->clip->test(x0 + i, y)) {
1387 pattern->getColor(x0 + i, y, color);
1388 if (softMask) {
1389 alpha2 = (int)(alpha *
1390 softMask->data[y * softMask->rowSize + x0 + i]);
1391 ialpha2 = 255 - alpha2;
1392 }
1393 (*blendFunc)(color, p, blend, bitmap->mode);
1394 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1395 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1396 if (!noClip) {
1397 updateModX(x0 + i);
1398 updateModY(y);
1399 }
1400 }
1401 p += 2;
1402 }
1403 }
1404 break;
1405
1406 case splashModeRGB8:
1407 case splashModeBGR8:
1408 p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1409 if (pattern->isStatic()) {
1410 pattern->getColor(0, 0, color);
1411 for (i = 0; i < n; ++i) {
1412 if (noClip || state->clip->test(x0 + i, y)) {
1413 if (softMask) {
1414 alpha2 = (int)(alpha *
1415 softMask->data[y * softMask->rowSize + x0 + i]);
1416 ialpha2 = 255 - alpha2;
1417 }
1418 (*blendFunc)(color, p, blend, bitmap->mode);
1419 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1420 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1421 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1422 if (!noClip) {
1423 updateModX(x0 + i);
1424 updateModY(y);
1425 }
1426 }
1427 p += 3;
1428 }
1429 } else {
1430 for (i = 0; i < n; ++i) {
1431 if (noClip || state->clip->test(x0 + i, y)) {
1432 pattern->getColor(x0 + i, y, color);
1433 if (softMask) {
1434 alpha2 = (int)(alpha *
1435 softMask->data[y * softMask->rowSize + x0 + i]);
1436 ialpha2 = 255 - alpha2;
1437 }
1438 (*blendFunc)(color, p, blend, bitmap->mode);
1439 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1440 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1441 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1442 if (!noClip) {
1443 updateModX(x0 + i);
1444 updateModY(y);
1445 }
1446 }
1447 p += 3;
1448 }
1449 }
1450 break;
1451
1452 case splashModeARGB8:
1453 case splashModeBGRA8:
1454 #if SPLASH_CMYK
1455 case splashModeCMYK8:
1456 #endif
1457 p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1458 if (pattern->isStatic()) {
1459 pattern->getColor(0, 0, color);
1460 for (i = 0; i < n; ++i) {
1461 if (noClip || state->clip->test(x0 + i, y)) {
1462 if (softMask) {
1463 alpha2 = (int)(alpha *
1464 softMask->data[y * softMask->rowSize + x0 + i]);
1465 ialpha2 = 255 - alpha2;
1466 }
1467 (*blendFunc)(color, p, blend, bitmap->mode);
1468 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1469 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1470 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1471 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1472 if (!noClip) {
1473 updateModX(x0 + i);
1474 updateModY(y);
1475 }
1476 }
1477 p += 4;
1478 }
1479 } else {
1480 for (i = 0; i < n; ++i) {
1481 if (noClip || state->clip->test(x0 + i, y)) {
1482 pattern->getColor(x0 + i, y, color);
1483 if (softMask) {
1484 alpha2 = (int)(alpha *
1485 softMask->data[y * softMask->rowSize + x0 + i]);
1486 ialpha2 = 255 - alpha2;
1487 }
1488 (*blendFunc)(color, p, blend, bitmap->mode);
1489 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1490 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1491 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1492 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1493 if (!noClip) {
1494 updateModX(x0 + i);
1495 updateModY(y);
1496 }
1497 }
1498 p += 4;
1499 }
1500 }
1501 break;
1502 #if SPLASH_CMYK
1503 case splashModeACMYK8:
1504 p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
1505 if (pattern->isStatic()) {
1506 pattern->getColor(0, 0, color);
1507 for (i = 0; i < n; ++i) {
1508 if (noClip || state->clip->test(x0 + i, y)) {
1509 if (softMask) {
1510 alpha2 = (int)(alpha *
1511 softMask->data[y * softMask->rowSize + x0 + i]);
1512 ialpha2 = 255 - alpha2;
1513 }
1514 (*blendFunc)(color, p, blend, bitmap->mode);
1515 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1516 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1517 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1518 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1519 p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
1520 if (!noClip) {
1521 updateModX(x0 + i);
1522 updateModY(y);
1523 }
1524 }
1525 p += 4;
1526 }
1527 } else {
1528 for (i = 0; i < n; ++i) {
1529 if (noClip || state->clip->test(x0 + i, y)) {
1530 pattern->getColor(x0 + i, y, color);
1531 if (softMask) {
1532 alpha2 = (int)(alpha *
1533 softMask->data[y * softMask->rowSize + x0 + i]);
1534 ialpha2 = 255 - alpha2;
1535 }
1536 (*blendFunc)(color, p, blend, bitmap->mode);
1537 p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1538 p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1539 p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1540 p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1541 p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
1542 if (!noClip) {
1543 updateModX(x0 + i);
1544 updateModY(y);
1545 }
1546 }
1547 p += 4;
1548 }
1549 }
1550 break;
1551 #endif
1552 }
1553
1554 } else {
1555 switch (bitmap->mode) {
1556 case splashModeMono1:
1557 p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1558 i = 0;
1559 if (pattern->isStatic()) {
1560 pattern->getColor(0, 0, color);
1561 if ((j = x0 & 7)) {
1562 mask = 0x80 >> j;
1563 for (; j < 8 && i < n; ++i, ++j) {
1564 if (noClip || state->clip->test(x0 + i, y)) {
1565 if (color[0]) {
1566 *p |= mask;
1567 } else {
1568 *p &= ~mask;
1569 }
1570 if (!noClip) {
1571 updateModX(x0 + i);
1572 updateModY(y);
1573 }
1574 }
1575 mask >>= 1;
1576 }
1577 ++p;
1578 }
1579 while (i < n) {
1580 mask = 0x80;
1581 for (j = 0; j < 8 && i < n; ++i, ++j) {
1582 if (noClip || state->clip->test(x0 + i, y)) {
1583 if (color[0]) {
1584 *p |= mask;
1585 } else {
1586 *p &= ~mask;
1587 }
1588 if (!noClip) {
1589 updateModX(x0 + i);
1590 updateModY(y);
1591 }
1592 }
1593 mask >>= 1;
1594 }
1595 ++p;
1596 }
1597 } else {
1598 if ((j = x0 & 7)) {
1599 mask = 0x80 >> j;
1600 for (; j < 8 && i < n; ++i, ++j) {
1601 if (noClip || state->clip->test(x0 + i, y)) {
1602 pattern->getColor(x0 + i, y, color);
1603 if (color[0]) {
1604 *p |= mask;
1605 } else {
1606 *p &= ~mask;
1607 }
1608 if (!noClip) {
1609 updateModX(x0 + i);
1610 updateModY(y);
1611 }
1612 }
1613 mask >>= 1;
1614 }
1615 ++p;
1616 }
1617 while (i < n) {
1618 mask = 0x80;
1619 for (j = 0; j < 8 && i < n; ++i, ++j) {
1620 if (noClip || state->clip->test(x0 + i, y)) {
1621 pattern->getColor(x0 + i, y, color);
1622 if (color[0]) {
1623 *p |= mask;
1624 } else {
1625 *p &= ~mask;
1626 }
1627 if (!noClip) {
1628 updateModX(x0 + i);
1629 updateModY(y);
1630 }
1631 }
1632 mask >>= 1;
1633 }
1634 ++p;
1635 }
1636 }
1637 break;
1638
1639 case splashModeMono8:
1640 p = &bitmap->data[y * bitmap->rowSize + x0];
1641 if (pattern->isStatic()) {
1642 pattern->getColor(0, 0, color);
1643 for (i = 0; i < n; ++i) {
1644 if (noClip || state->clip->test(x0 + i, y)) {
1645 *p = color[0];
1646 if (!noClip) {
1647 updateModX(x0 + i);
1648 updateModY(y);
1649 }
1650 }
1651 ++p;
1652 }
1653 } else {
1654 for (i = 0; i < n; ++i) {
1655 if (noClip || state->clip->test(x0 + i, y)) {
1656 pattern->getColor(x0 + i, y, color);
1657 *p = color[0];
1658 if (!noClip) {
1659 updateModX(x0 + i);
1660 updateModY(y);
1661 }
1662 }
1663 ++p;
1664 }
1665 }
1666 break;
1667
1668 case splashModeAMono8:
1669 p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
1670 if (pattern->isStatic()) {
1671 pattern->getColor(0, 0, color);
1672 for (i = 0; i < n; ++i) {
1673 if (noClip || state->clip->test(x0 + i, y)) {
1674 p[0] = color[0];
1675 p[1] = color[1];
1676 if (!noClip) {
1677 updateModX(x0 + i);
1678 updateModY(y);
1679 }
1680 }
1681 p += 2;
1682 }
1683 } else {
1684 for (i = 0; i < n; ++i) {
1685 if (noClip || state->clip->test(x0 + i, y)) {
1686 pattern->getColor(x0 + i, y, color);
1687 p[0] = color[0];
1688 p[1] = color[1];
1689 if (!noClip) {
1690 updateModX(x0 + i);
1691 updateModY(y);
1692 }
1693 }
1694 p += 2;
1695 }
1696 }
1697 break;
1698
1699 case splashModeRGB8:
1700 case splashModeBGR8:
1701 p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1702 if (pattern->isStatic()) {
1703 pattern->getColor(0, 0, color);
1704 for (i = 0; i < n; ++i) {
1705 if (noClip || state->clip->test(x0 + i, y)) {
1706 p[0] = color[0];
1707 p[1] = color[1];
1708 p[2] = color[2];
1709 if (!noClip) {
1710 updateModX(x0 + i);
1711 updateModY(y);
1712 }
1713 }
1714 p += 3;
1715 }
1716 } else {
1717 for (i = 0; i < n; ++i) {
1718 if (noClip || state->clip->test(x0 + i, y)) {
1719 pattern->getColor(x0 + i, y, color);
1720 p[0] = color[0];
1721 p[1] = color[1];
1722 p[2] = color[2];
1723 if (!noClip) {
1724 updateModX(x0 + i);
1725 updateModY(y);
1726 }
1727 }
1728 p += 3;
1729 }
1730 }
1731 break;
1732
1733 case splashModeARGB8:
1734 case splashModeBGRA8:
1735 #if SPLASH_CMYK
1736 case splashModeCMYK8:
1737 #endif
1738 p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1739 if (pattern->isStatic()) {
1740 pattern->getColor(0, 0, color);
1741 for (i = 0; i < n; ++i) {
1742 if (noClip || state->clip->test(x0 + i, y)) {
1743 p[0] = color[0];
1744 p[1] = color[1];
1745 p[2] = color[2];
1746 p[3] = color[3];
1747 if (!noClip) {
1748 updateModX(x0 + i);
1749 updateModY(y);
1750 }
1751 }
1752 p += 4;
1753 }
1754 } else {
1755 for (i = 0; i < n; ++i) {
1756 if (noClip || state->clip->test(x0 + i, y)) {
1757 pattern->getColor(x0 + i, y, color);
1758 p[0] = color[0];
1759 p[1] = color[1];
1760 p[2] = color[2];
1761 p[3] = color[3];
1762 if (!noClip) {
1763 updateModX(x0 + i);
1764 updateModY(y);
1765 }
1766 }
1767 p += 4;
1768 }
1769 }
1770 break;
1771 #if SPLASH_CMYK
1772 case splashModeACMYK8:
1773 p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
1774 if (pattern->isStatic()) {
1775 pattern->getColor(0, 0, color);
1776 for (i = 0; i < n; ++i) {
1777 if (noClip || state->clip->test(x0 + i, y)) {
1778 p[0] = color[0];
1779 p[1] = color[1];
1780 p[2] = color[2];
1781 p[3] = color[3];
1782 p[4] = color[4];
1783 if (!noClip) {
1784 updateModX(x0 + i);
1785 updateModY(y);
1786 }
1787 }
1788 p += 4;
1789 }
1790 } else {
1791 for (i = 0; i < n; ++i) {
1792 if (noClip || state->clip->test(x0 + i, y)) {
1793 pattern->getColor(x0 + i, y, color);
1794 p[0] = color[0];
1795 p[1] = color[1];
1796 p[2] = color[2];
1797 p[3] = color[3];
1798 p[4] = color[4];
1799 if (!noClip) {
1800 updateModX(x0 + i);
1801 updateModY(y);
1802 }
1803 }
1804 p += 4;
1805 }
1806 }
1807 break;
1808 #endif
1809 }
1810 }
1811 }
1812
1813 void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern,
1814 GBool noClip) {
1815 SplashColor color;
1816 SplashColorPtr p;
1817 Guchar mask;
1818 int i, j, n;
1819
1820 n = x1 - x0 + 1;
1821
1822 if (noClip) {
1823 updateModX(x0);
1824 updateModX(x1);
1825 updateModY(y);
1826 }
1827
1828 switch (bitmap->mode) {
1829 case splashModeMono1:
1830 p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1831 i = 0;
1832 if ((j = x0 & 7)) {
1833 mask = 0x80 >> j;
1834 for (; j < 8 && i < n; ++i, ++j) {
1835 if (noClip || state->clip->test(x0 + i, y)) {
1836 pattern->getColor(x0 + i, y, color);
1837 if (color[0]) {
1838 *p ^= mask;
1839 }
1840 if (!noClip) {
1841 updateModX(x0 + i);
1842 updateModY(y);
1843 }
1844 }
1845 mask >>= 1;
1846 }
1847 ++p;
1848 }
1849 while (i < n) {
1850 mask = 0x80;
1851 for (j = 0; j < 8 && i < n; ++i, ++j) {
1852 if (noClip || state->clip->test(x0 + i, y)) {
1853 pattern->getColor(x0 + i, y, color);
1854 if (color[0]) {
1855 *p ^= mask;
1856 }
1857 if (!noClip) {
1858 updateModX(x0 + i);
1859 updateModY(y);
1860 }
1861 }
1862 mask >>= 1;
1863 }
1864 ++p;
1865 }
1866 break;
1867
1868 case splashModeMono8:
1869 p = &bitmap->data[y * bitmap->rowSize + x0];
1870 for (i = 0; i < n; ++i) {
1871 if (noClip || state->clip->test(x0 + i, y)) {
1872 pattern->getColor(x0 + i, y, color);
1873 *p ^= color[0];
1874 if (!noClip) {
1875 updateModX(x0 + i);
1876 updateModY(y);
1877 }
1878 }
1879 ++p;
1880 }
1881 break;
1882
1883 case splashModeAMono8:
1884 p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
1885 for (i = 0; i < n; ++i) {
1886 if (noClip || state->clip->test(x0 + i, y)) {
1887 pattern->getColor(x0 + i, y, color);
1888 p[0] ^= color[0];
1889 p[1] ^= color[1];
1890 if (!noClip) {
1891 updateModX(x0 + i);
1892 updateModY(y);
1893 }
1894 }
1895 p += 2;
1896 }
1897 break;
1898
1899 case splashModeRGB8:
1900 case splashModeBGR8:
1901 p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1902 for (i = 0; i < n; ++i) {
1903 if (noClip || state->clip->test(x0 + i, y)) {
1904 pattern->getColor(x0 + i, y, color);
1905 p[0] ^= color[0];
1906 p[1] ^= color[1];
1907 p[2] ^= color[2];
1908 if (!noClip) {
1909 updateModX(x0 + i);
1910 updateModY(y);
1911 }
1912 }
1913 p += 3;
1914 }
1915 break;
1916
1917 case splashModeARGB8:
1918 case splashModeBGRA8:
1919 #if SPLASH_CMYK
1920 case splashModeCMYK8:
1921 #endif
1922 p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1923 for (i = 0; i < n; ++i) {
1924 if (noClip || state->clip->test(x0 + i, y)) {
1925 pattern->getColor(x0 + i, y, color);
1926 p[0] ^= color[0];
1927 p[1] ^= color[1];
1928 p[2] ^= color[2];
1929 p[3] ^= color[3];
1930 if (!noClip) {
1931 updateModX(x0 + i);
1932 updateModY(y);
1933 }
1934 }
1935 p += 4;
1936 }
1937 break;
1938 #if SPLASH_CMYK
1939 case splashModeACMYK8:
1940 p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
1941 for (i = 0; i < n; ++i) {
1942 if (noClip || state->clip->test(x0 + i, y)) {
1943 pattern->getColor(x0 + i, y, color);
1944 p[0] ^= color[0];
1945 p[1] ^= color[1];
1946 p[2] ^= color[2];
1947 p[3] ^= color[3];
1948 p[4] ^= color[4];
1949 if (!noClip) {
1950 updateModX(x0 + i);
1951 updateModY(y);
1952 }
1953 }
1954 p += 4;
1955 }
1956 break;
1957 #endif
1958 }
1959 }
1960
1961 SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
1962 int c, SplashFont *font) {
1963 SplashGlyphBitmap glyph;
1964 int x0, y0, xFrac, yFrac;
1965 SplashError err;
1966
1967 if (debugMode) {
1968 printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
1969 (double)x, (double)y, c, c, c);
1970 }
1971 x0 = splashFloor(x);
1972 xFrac = splashFloor((x - x0) * splashFontFraction);
1973 y0 = splashFloor(y);
1974 yFrac = splashFloor((y - y0) * splashFontFraction);
1975 if (!font->getGlyph(c, xFrac, yFrac, &glyph)) {
1976 return splashErrNoGlyph;
1977 }
1978 err = fillGlyph(x, y, &glyph);
1979 if (glyph.freeData) {
1980 gfree(glyph.data);
1981 }
1982 return err;
1983 }
1984
1985 SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
1986 SplashGlyphBitmap *glyph) {
1987 SplashBlendFunc blendFunc;
1988 int alpha0, alpha, ialpha;
1989 Guchar *p;
1990 SplashColor fg, dest, blend;
1991 SplashColorPtr pix;
1992 SplashClipResult clipRes;
1993 GBool noClip;
1994 Guchar t;
1995 int x0, y0, x1, y1, xx, xx1, yy;
1996
1997 x0 = splashFloor(x);
1998 y0 = splashFloor(y);
1999
2000 if ((clipRes = state->clip->testRect(x0 - glyph->x,
2001 y0 - glyph->y,
2002 x0 - glyph->x + glyph->w - 1,
2003 y0 - glyph->y + glyph->h - 1))
2004 != splashClipAllOutside) {
2005 noClip = clipRes == splashClipAllInside;
2006
2007 if (noClip) {
2008 updateModX(x0 - glyph->x);
2009 updateModX(x0 - glyph->x + glyph->w - 1);
2010 updateModY(y0 - glyph->y);
2011 updateModY(y0 - glyph->y + glyph->h - 1);
2012 }
2013
2014 //~ optimize this
2015 if (state->fillAlpha != 1 || softMask || state->blendFunc) {
2016 blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
2017 if (glyph->aa) {
2018 p = glyph->data;
2019 for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2020 for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
2021 alpha = *p++;
2022 if (softMask) {
2023 alpha = (int)(alpha * state->fillAlpha *
2024 softMask->data[y1 * softMask->rowSize + x1]);
2025 } else {
2026 alpha = (int)(alpha * state->fillAlpha);
2027 }
2028 if (alpha > 0) {
2029 if (noClip || state->clip->test(x1, y1)) {
2030 ialpha = 255 - alpha;
2031 state->fillPattern->getColor(x1, y1, fg);
2032 switch (bitmap->mode) {
2033 case splashModeMono1:
2034 pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2035 dest[0] = (*pix >> (7 - (x1 & 7))) & 1;
2036 (*blendFunc)(fg, dest, blend, bitmap->mode);
2037 t = (alpha * blend[0] + ialpha * dest[0]) >> 8;
2038 if (t) {
2039 *pix |= 0x80 >> (x1 & 7);
2040 } else {
2041 *pix &= ~(0x80 >> (x1 & 7));
2042 }
2043 break;
2044 case splashModeMono8:
2045 pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2046 (*blendFunc)(fg, pix, blend, bitmap->mode);
2047 // note: floor(x / 255) = x >> 8 (for 16-bit x)
2048 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2049 break;
2050 case splashModeAMono8:
2051 pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2052 (*blendFunc)(fg, pix, blend, bitmap->mode);
2053 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2054 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2055 break;
2056 case splashModeRGB8:
2057 case splashModeBGR8:
2058 pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2059 (*blendFunc)(fg, pix, blend, bitmap->mode);
2060 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2061 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2062 pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2063 break;
2064 case splashModeARGB8:
2065 case splashModeBGRA8:
2066 #if SPLASH_CMYK
2067 case splashModeCMYK8:
2068 #endif
2069 pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2070 (*blendFunc)(fg, pix, blend, bitmap->mode);
2071 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2072 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2073 pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2074 pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2075 break;
2076 #if SPLASH_CMYK
2077 case splashModeACMYK8:
2078 pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2079 (*blendFunc)(fg, pix, blend, bitmap->mode);
2080 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2081 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2082 pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2083 pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2084 pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8;
2085 break;
2086 #endif
2087 }
2088 if (!noClip) {
2089 updateModX(x1);
2090 updateModY(y1);
2091 }
2092 }
2093 }
2094 }
2095 }
2096
2097 } else {
2098 p = glyph->data;
2099 for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2100 for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
2101 alpha0 = *p++;
2102 for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
2103 if (alpha0 & 0x80) {
2104 if (noClip || state->clip->test(x1, y1)) {
2105 if (softMask) {
2106 alpha = (int)(state->fillAlpha *
2107 softMask->data[y1 * softMask->rowSize + x1]);
2108 } else {
2109 alpha = (int)(state->fillAlpha * 255);
2110 }
2111 ialpha = 255 - alpha;
2112 state->fillPattern->getColor(x1, y1, fg);
2113 switch (bitmap->mode) {
2114 case splashModeMono1:
2115 pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2116 dest[0] = (*pix >> (7 - (x1 & 7))) & 1;
2117 (*blendFunc)(fg, dest, blend, bitmap->mode);
2118 t = (alpha * blend[0] + ialpha * dest[0]) >> 8;
2119 if (t) {
2120 *pix |= 0x80 >> (x1 & 7);
2121 } else {
2122 *pix &= ~(0x80 >> (x1 & 7));
2123 }
2124 break;
2125 case splashModeMono8:
2126 pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2127 (*blendFunc)(fg, pix, blend, bitmap->mode);
2128 // note: floor(x / 255) = x >> 8 (for 16-bit x)
2129 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2130 break;
2131 case splashModeAMono8:
2132 pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2133 (*blendFunc)(fg, pix, blend, bitmap->mode);
2134 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2135 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2136 break;
2137 case splashModeRGB8:
2138 case splashModeBGR8:
2139 pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2140 (*blendFunc)(fg, pix, blend, bitmap->mode);
2141 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2142 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2143 pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2144 break;
2145 case splashModeARGB8:
2146 case splashModeBGRA8:
2147 #if SPLASH_CMYK
2148 case splashModeCMYK8:
2149 #endif
2150 pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2151 (*blendFunc)(fg, pix, blend, bitmap->mode);
2152 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2153 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2154 pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2155 pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2156 break;
2157 #if SPLASH_CMYK
2158 case splashModeACMYK8:
2159 pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2160 (*blendFunc)(fg, pix, blend, bitmap->mode);
2161 pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2162 pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2163 pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2164 pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2165 pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8;
2166 break;
2167 #endif
2168 }
2169 if (!noClip) {
2170 updateModX(x1);
2171 updateModY(y1);
2172 }
2173 }
2174 }
2175 alpha0 <<= 1;
2176 }
2177 }
2178 }
2179 }
2180
2181 } else {
2182 if (glyph->aa) {
2183 p = glyph->data;
2184 for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2185 for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
2186 alpha = *p++;
2187 if (alpha > 0) {
2188 if (noClip || state->clip->test(x1, y1)) {
2189 ialpha = 255 - alpha;
2190 state->fillPattern->getColor(x1, y1, fg);
2191 switch (bitmap->mode) {
2192 case splashModeMono1:
2193 if (alpha >= 0x80) {
2194 pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2195 if (fg[0]) {
2196 *pix |= 0x80 >> (x1 & 7);
2197 } else {
2198 *pix &= ~(0x80 >> (x1 & 7));
2199 }
2200 }
2201 break;
2202 case splashModeMono8:
2203 pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2204 // note: floor(x / 255) = x >> 8 (for 16-bit x)
2205 pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2206 break;
2207 case splashModeAMono8:
2208 pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2209 pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2210 pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2211 break;
2212 case splashModeRGB8:
2213 case splashModeBGR8:
2214 pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2215 pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2216 pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2217 pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
2218 break;
2219 case splashModeARGB8:
2220 case splashModeBGRA8:
2221 #if SPLASH_CMYK
2222 case splashModeCMYK8:
2223 #endif
2224 pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2225 pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2226 pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2227 pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
2228 pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8;
2229 break;
2230 #if SPLASH_CMYK
2231 case splashModeACMYK8:
2232 pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2233 pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2234 pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2235 pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
2236 pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8;
2237 pix[4] = (alpha * fg[4] + ialpha * pix[4]) >> 8;
2238 break;
2239 #endif
2240 }
2241 if (!noClip) {
2242 updateModX(x1);
2243 updateModY(y1);
2244 }
2245 }
2246 }
2247 }
2248 }
2249
2250 } else {
2251 p = glyph->data;
2252 for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2253 for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
2254 alpha0 = *p++;
2255 for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
2256 if (alpha0 & 0x80) {
2257 if (noClip || state->clip->test(x1, y1)) {
2258 state->fillPattern->getColor(x1, y1, fg);
2259 switch (bitmap->mode) {
2260 case splashModeMono1:
2261 pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2262 if (fg[0]) {
2263 *pix |= 0x80 >> (x1 & 7);
2264 } else {
2265 *pix &= ~(0x80 >> (x1 & 7));
2266 }
2267 break;
2268 case splashModeMono8:
2269 pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2270 pix[0] = fg[0];
2271 break;
2272 case splashModeAMono8:
2273 pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2274 pix[0] = fg[0];
2275 pix[1] = fg[1];
2276 break;
2277 case splashModeRGB8:
2278 case splashModeBGR8:
2279 pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2280 pix[0] = fg[0];
2281 pix[1] = fg[1];
2282 pix[2] = fg[2];
2283 break;
2284 case splashModeARGB8:
2285 case splashModeBGRA8:
2286 #if SPLASH_CMYK
2287 case splashModeCMYK8:
2288 #endif
2289 pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2290 pix[0] = fg[0];
2291 pix[1] = fg[1];
2292 pix[2] = fg[2];
2293 pix[3] = fg[3];
2294 break;
2295 #if SPLASH_CMYK
2296 case splashModeACMYK8:
2297 pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2298 pix[0] = fg[0];
2299 pix[1] = fg[1];
2300 pix[2] = fg[2];
2301 pix[3] = fg[3];
2302 pix[4] = fg[4];
2303 break;
2304 #endif
2305 }
2306 if (!noClip) {
2307 updateModX(x1);
2308 updateModY(y1);
2309 }
2310 }
2311 }
2312 alpha0 <<= 1;
2313 }
2314 }
2315 }
2316 }
2317 }
2318 }
2319 opClipRes = clipRes;
2320
2321 return splashOk;
2322 }
2323
2324 SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
2325 int w, int h, SplashCoord *mat) {
2326 GBool rot;
2327 SplashCoord xScale, yScale, xShear, yShear, yShear1;
2328 int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
2329 int ulx, uly, llx, lly, urx, ury, lrx, lry;
2330 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2331 int xMin, xMax, yMin, yMax;
2332 SplashClipResult clipRes, clipRes2;
2333 int yp, yq, yt, yStep, lastYStep;
2334 int xp, xq, xt, xStep, xSrc;
2335 int k1, spanXMin, spanXMax, spanY;
2336 SplashColorPtr pixBuf, p;
2337 int pixAcc;
2338 SplashCoord alpha;
2339 int x, y, x1, x2, y2;
2340 SplashCoord y1;
2341 int n, m, i, j;
2342
2343 if (debugMode) {
2344 printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2345 w, h, (double)mat[0], (double)mat[1], (double)mat[2],
2346 (double)mat[3], (double)mat[4], (double)mat[5]);
2347 }
2348
2349 // check for singular matrix
2350 if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
2351 return splashErrSingularMatrix;
2352 }
2353
2354 // compute scale, shear, rotation, translation parameters
2355 rot = splashAbs(mat[1]) > splashAbs(mat[0]);
2356 if (rot) {
2357 xScale = -mat[1];
2358 yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
2359 xShear = -mat[3] / yScale;
2360 yShear = -mat[0] / mat[1];
2361 } else {
2362 xScale = mat[0];
2363 yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
2364 xShear = mat[2] / yScale;
2365 yShear = mat[1] / mat[0];
2366 }
2367 // the +/-0.01 in these computations is to avoid floating point
2368 // precision problems which can lead to gaps between image stripes
2369 // (it can cause image stripes to overlap, but that's a much less
2370 // visible problem)
2371 if (xScale >= 0) {
2372 tx = splashRound(mat[4] - 0.01);
2373 tx2 = splashRound(mat[4] + xScale + 0.01) - 1;
2374 } else {
2375 tx = splashRound(mat[4] + 0.01) - 1;
2376 tx2 = splashRound(mat[4] + xScale - 0.01);
2377 }
2378 scaledWidth = abs(tx2 - tx) + 1;
2379 if (scaledWidth == 0) {
2380 // technically, this should draw nothing, but it generally seems
2381 // better to draw a one-pixel-wide stripe rather than throwing it
2382 // away
2383 scaledWidth = 1;
2384 }
2385 if (yScale >= 0) {
2386 ty = splashRound(mat[5] - 0.01);
2387 ty2 = splashRound(mat[5] + yScale + 0.01) - 1;
2388 } else {
2389 ty = splashRound(mat[5] + 0.01) - 1;
2390 ty2 = splashRound(mat[5] + yScale - 0.01);
2391 }
2392 scaledHeight = abs(ty2 - ty) + 1;
2393 if (scaledHeight == 0) {
2394 // technically, this should draw nothing, but it generally seems
2395 // better to draw a one-pixel-wide stripe rather than throwing it
2396 // away
2397 scaledHeight = 1;
2398 }
2399 xSign = (xScale < 0) ? -1 : 1;
2400 ySign = (yScale < 0) ? -1 : 1;
2401 yShear1 = (SplashCoord)xSign * yShear;
2402
2403 // clipping
2404 ulx1 = 0;
2405 uly1 = 0;
2406 urx1 = xSign * (scaledWidth - 1);
2407 ury1 = (int)(yShear * urx1);
2408 llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2409 lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2410 lrx1 = xSign * (scaledWidth - 1) +
2411 splashRound(xShear * ySign * (scaledHeight - 1));
2412 lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2413 if (rot) {
2414 ulx = tx + uly1; uly = ty - ulx1;
2415 urx = tx + ury1; ury = ty - urx1;
2416 llx = tx + lly1; lly = ty - llx1;
2417 lrx = tx + lry1; lry = ty - lrx1;
2418 } else {
2419 ulx = tx + ulx1; uly = ty + uly1;
2420 urx = tx + urx1; ury = ty + ury1;
2421 llx = tx + llx1; lly = ty + lly1;
2422 lrx = tx + lrx1; lry = ty + lry1;
2423 }
2424 xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2425 : (llx < lrx) ? llx : lrx
2426 : (urx < llx) ? (urx < lrx) ? urx : lrx
2427 : (llx < lrx) ? llx : lrx;
2428 xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2429 : (llx > lrx) ? llx : lrx
2430 : (urx > llx) ? (urx > lrx) ? urx : lrx
2431 : (llx > lrx) ? llx : lrx;
2432 yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2433 : (lly < lry) ? lly : lry
2434 : (ury < lly) ? (ury < lry) ? ury : lry
2435 : (lly < lry) ? lly : lry;
2436 yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2437 : (lly > lry) ? lly : lry
2438 : (ury > lly) ? (ury > lry) ? ury : lry
2439 : (lly > lry) ? lly : lry;
2440 clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2441 opClipRes = clipRes;
2442
2443 // compute Bresenham parameters for x and y scaling
2444 yp = h / scaledHeight;
2445 yq = h % scaledHeight;
2446 xp = w / scaledWidth;
2447 xq = w % scaledWidth;
2448
2449 // allocate pixel buffer
2450 pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w);
2451
2452 // init y scale Bresenham
2453 yt = 0;
2454 lastYStep = 1;
2455
2456 for (y = 0; y < scaledHeight; ++y) {
2457
2458 // y scale Bresenham
2459 yStep = yp;
2460 yt += yq;
2461 if (yt >= scaledHeight) {
2462 yt -= scaledHeight;
2463 ++yStep;
2464 }
2465
2466 // read row(s) from image
2467 n = (yp > 0) ? yStep : lastYStep;
2468 if (n > 0) {
2469 p = pixBuf;
2470 for (i = 0; i < n; ++i) {
2471 (*src)(srcData, p);
2472 p += w;
2473 }
2474 }
2475 lastYStep = yStep;
2476
2477 // loop-invariant constants
2478 k1 = splashRound(xShear * ySign * y);
2479
2480 // clipping test
2481 if (clipRes != splashClipAllInside &&
2482 !rot &&
2483 (int)(yShear * k1) ==
2484 (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2485 if (xSign > 0) {
2486 spanXMin = tx + k1;
2487 spanXMax = spanXMin + (scaledWidth - 1);
2488 } else {
2489 spanXMax = tx + k1;
2490 spanXMin = spanXMax - (scaledWidth - 1);
2491 }
2492 spanY = ty + ySign * y + (int)(yShear * k1);
2493 clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2494 if (clipRes2 == splashClipAllOutside) {
2495 continue;
2496 }
2497 } else {
2498 clipRes2 = clipRes;
2499 }
2500
2501 // init x scale Bresenham
2502 xt = 0;
2503 xSrc = 0;
2504
2505 // x shear
2506 x1 = k1;
2507
2508 // y shear
2509 y1 = (SplashCoord)ySign * y + yShear * x1;
2510 // this is a kludge: if yShear1 is negative, then (int)y1 would
2511 // change immediately after the first pixel, which is not what we
2512 // want
2513 if (yShear1 < 0) {
2514 y1 += 0.999;
2515 }
2516
2517 // loop-invariant constants
2518 n = yStep > 0 ? yStep : 1;
2519
2520 for (x = 0; x < scaledWidth; ++x) {
2521
2522 // x scale Bresenham
2523 xStep = xp;
2524 xt += xq;
2525 if (xt >= scaledWidth) {
2526 xt -= scaledWidth;
2527 ++xStep;
2528 }
2529
2530 // rotation
2531 if (rot) {
2532 x2 = (int)y1;
2533 y2 = -x1;
2534 } else {
2535 x2 = x1;
2536 y2 = (int)y1;
2537 }
2538
2539 // compute the alpha value for (x,y) after the x and y scaling
2540 // operations
2541 m = xStep > 0 ? xStep : 1;
2542 p = pixBuf + xSrc;
2543 pixAcc = 0;
2544 for (i = 0; i < n; ++i) {
2545 for (j = 0; j < m; ++j) {
2546 pixAcc += *p++;
2547 }
2548 p += w - m;
2549 }
2550
2551 // blend fill color with background
2552 if (pixAcc != 0) {
2553 if (pixAcc == n * m) {
2554 drawPixel(tx + x2, ty + y2, state->fillPattern, state->fillAlpha,
2555 clipRes2 == splashClipAllInside);
2556 } else {
2557 alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m);
2558 drawPixel(tx + x2, ty + y2, state->fillPattern,
2559 state->fillAlpha * alpha,
2560 clipRes2 == splashClipAllInside);
2561 }
2562 }
2563
2564 // x scale Bresenham
2565 xSrc += xStep;
2566
2567 // x shear
2568 x1 += xSign;
2569
2570 // y shear
2571 y1 += yShear1;
2572 }
2573 }
2574
2575 // free memory
2576 gfree(pixBuf);
2577
2578 return splashOk;
2579 }
2580
2581 SplashError Splash::drawImage(SplashImageSource src, void *srcData,
2582 SplashColorMode srcMode,
2583 int w, int h, SplashCoord *mat) {
2584 GBool ok, rot, halftone, srcAlpha;
2585 SplashCoord xScale, yScale, xShear, yShear, yShear1;
2586 int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
2587 int ulx, uly, llx, lly, urx, ury, lrx, lry;
2588 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2589 int xMin, xMax, yMin, yMax;
2590 SplashClipResult clipRes, clipRes2;
2591 int yp, yq, yt, yStep, lastYStep;
2592 int xp, xq, xt, xStep, xSrc;
2593 int k1, spanXMin, spanXMax, spanY;
2594 SplashColorPtr pixBuf, p;
2595 SplashColor pix;
2596 #if SPLASH_CMYK
2597 int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
2598 #else
2599 int pixAcc0, pixAcc1, pixAcc2;
2600 #endif
2601 int alphaAcc;
2602 SplashCoord pixMul, alphaMul, alpha;
2603 int x, y, x1, x2, y2;
2604 SplashCoord y1;
2605 int nComps, n, m, i, j;
2606
2607 if (debugMode) {
2608 printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2609 srcMode, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
2610 (double)mat[3], (double)mat[4], (double)mat[5]);
2611 }
2612
2613 // check color modes
2614 ok = gFalse; // make gcc happy
2615 nComps = 0; // make gcc happy
2616 halftone = gFalse;
2617 srcAlpha = gFalse;
2618 switch (bitmap->mode) {
2619 case splashModeMono1:
2620 ok = srcMode == splashModeMono1 || srcMode == splashModeMono8 ||
2621 srcMode == splashModeAMono8;
2622 halftone = srcMode == splashModeMono8 || srcMode == splashModeAMono8;
2623 srcAlpha = srcMode == splashModeAMono8;
2624 nComps = srcAlpha ? 2 : 1;
2625 break;
2626 case splashModeMono8:
2627 ok = srcMode == splashModeMono8 || srcMode == splashModeAMono8;
2628 srcAlpha = srcMode == splashModeAMono8;
2629 nComps = srcAlpha ? 2 : 1;
2630 break;
2631 case splashModeAMono8:
2632 //~ not implemented yet
2633 ok = gFalse;
2634 nComps = 2;
2635 break;
2636 case splashModeRGB8:
2637 ok = srcMode == splashModeRGB8 || srcMode == splashModeARGB8;
2638 srcAlpha = srcMode == splashModeARGB8;
2639 nComps = srcAlpha ? 4 : 3;
2640 break;
2641 case splashModeBGR8:
2642 ok = srcMode == splashModeBGR8 || srcMode == splashModeBGRA8;
2643 srcAlpha = srcMode == splashModeBGRA8;
2644 nComps = srcAlpha ? 4 : 3;
2645 break;
2646 #if SPLASH_CMYK
2647 case splashModeCMYK8:
2648 ok = srcMode == splashModeCMYK8 || srcMode == splashModeACMYK8;
2649 srcAlpha = srcMode == splashModeACMYK8;
2650 nComps = srcAlpha ? 5 : 4;
2651 break;
2652 #endif
2653 case splashModeARGB8:
2654 case splashModeBGRA8:
2655 #if SPLASH_CMYK
2656 case splashModeACMYK8:
2657 #endif
2658 //~ not implemented yet
2659 ok = gFalse;
2660 nComps = 4;
2661 break;
2662 }
2663 if (!ok) {
2664 return splashErrModeMismatch;
2665 }
2666
2667 // check for singular matrix
2668 if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
2669 return splashErrSingularMatrix;
2670 }
2671
2672 // compute scale, shear, rotation, translation parameters
2673 rot = splashAbs(mat[1]) > splashAbs(mat[0]);
2674 if (rot) {
2675 xScale = -mat[1];
2676 yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
2677 xShear = -mat[3] / yScale;
2678 yShear = -mat[0] / mat[1];
2679 } else {
2680 xScale = mat[0];
2681 yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
2682 xShear = mat[2] / yScale;
2683 yShear = mat[1] / mat[0];
2684 }
2685 // the +/-0.01 in these computations is to avoid floating point
2686 // precision problems which can lead to gaps between image stripes
2687 // (it can cause image stripes to overlap, but that's a much less
2688 // visible problem)
2689 if (xScale >= 0) {
2690 tx = splashRound(mat[4] - 0.01);
2691 tx2 = splashRound(mat[4] + xScale + 0.01) - 1;
2692 } else {
2693 tx = splashRound(mat[4] + 0.01) - 1;
2694 tx2 = splashRound(mat[4] + xScale - 0.01);
2695 }
2696 scaledWidth = abs(tx2 - tx) + 1;
2697 if (scaledWidth == 0) {
2698 // technically, this should draw nothing, but it generally seems
2699 // better to draw a one-pixel-wide stripe rather than throwing it
2700 // away
2701 scaledWidth = 1;
2702 }
2703 if (yScale >= 0) {
2704 ty = splashRound(mat[5] - 0.01);
2705 ty2 = splashRound(mat[5] + yScale + 0.01) - 1;
2706 } else {
2707 ty = splashRound(mat[5] + 0.01) - 1;
2708 ty2 = splashRound(mat[5] + yScale - 0.01);
2709 }
2710 scaledHeight = abs(ty2 - ty) + 1;
2711 if (scaledHeight == 0) {
2712 // technically, this should draw nothing, but it generally seems
2713 // better to draw a one-pixel-wide stripe rather than throwing it
2714 // away
2715 scaledHeight = 1;
2716 }
2717 xSign = (xScale < 0) ? -1 : 1;
2718 ySign = (yScale < 0) ? -1 : 1;
2719 yShear1 = (SplashCoord)xSign * yShear;
2720
2721 // clipping
2722 ulx1 = 0;
2723 uly1 = 0;
2724 urx1 = xSign * (scaledWidth - 1);
2725 ury1 = (int)(yShear * urx1);
2726 llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2727 lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2728 lrx1 = xSign * (scaledWidth - 1) +
2729 splashRound(xShear * ySign * (scaledHeight - 1));
2730 lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2731 if (rot) {
2732 ulx = tx + uly1; uly = ty - ulx1;
2733 urx = tx + ury1; ury = ty - urx1;
2734 llx = tx + lly1; lly = ty - llx1;
2735 lrx = tx + lry1; lry = ty - lrx1;
2736 } else {
2737 ulx = tx + ulx1; uly = ty + uly1;
2738 urx = tx + urx1; ury = ty + ury1;
2739 llx = tx + llx1; lly = ty + lly1;
2740 lrx = tx + lrx1; lry = ty + lry1;
2741 }
2742 xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2743 : (llx < lrx) ? llx : lrx
2744 : (urx < llx) ? (urx < lrx) ? urx : lrx
2745 : (llx < lrx) ? llx : lrx;
2746 xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2747 : (llx > lrx) ? llx : lrx
2748 : (urx > llx) ? (urx > lrx) ? urx : lrx
2749 : (llx > lrx) ? llx : lrx;
2750 yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2751 : (lly < lry) ? lly : lry
2752 : (ury < lly) ? (ury < lry) ? ury : lry
2753 : (lly < lry) ? lly : lry;
2754 yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2755 : (lly > lry) ? lly : lry
2756 : (ury > lly) ? (ury > lry) ? ury : lry
2757 : (lly > lry) ? lly : lry;
2758 clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2759 opClipRes = clipRes;
2760 if (clipRes == splashClipAllOutside) {
2761 return splashOk;
2762 }
2763
2764 // compute Bresenham parameters for x and y scaling
2765 yp = h / scaledHeight;
2766 yq = h % scaledHeight;
2767 xp = w / scaledWidth;
2768 xq = w % scaledWidth;
2769
2770 // allocate pixel buffer
2771 pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps);
2772
2773 pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
2774 #if SPLASH_CMYK
2775 pixAcc3 = 0; // make gcc happy
2776 #endif
2777
2778 if (srcAlpha) {
2779
2780 // init y scale Bresenham
2781 yt = 0;
2782 lastYStep = 1;
2783
2784 for (y = 0; y < scaledHeight; ++y) {
2785
2786 // y scale Bresenham
2787 yStep = yp;
2788 yt += yq;
2789 if (yt >= scaledHeight) {
2790 yt -= scaledHeight;
2791 ++yStep;
2792 }
2793
2794 // read row(s) from image
2795 n = (yp > 0) ? yStep : lastYStep;
2796 if (n > 0) {
2797 p = pixBuf;
2798 for (i = 0; i < n; ++i) {
2799 (*src)(srcData, p);
2800 p += w * nComps;
2801 }
2802 }
2803 lastYStep = yStep;
2804
2805 // loop-invariant constants
2806 k1 = splashRound(xShear * ySign * y);
2807
2808 // clipping test
2809 if (clipRes != splashClipAllInside &&
2810 !rot &&
2811 (int)(yShear * k1) ==
2812 (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2813 if (xSign > 0) {
2814 spanXMin = tx + k1;
2815 spanXMax = spanXMin + (scaledWidth - 1);
2816 } else {
2817 spanXMax = tx + k1;
2818 spanXMin = spanXMax - (scaledWidth - 1);
2819 }
2820 spanY = ty + ySign * y + (int)(yShear * k1);
2821 clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2822 if (clipRes2 == splashClipAllOutside) {
2823 continue;
2824 }
2825 } else {
2826 clipRes2 = clipRes;
2827 }
2828
2829 // init x scale Bresenham
2830 xt = 0;
2831 xSrc = 0;
2832
2833 // x shear
2834 x1 = k1;
2835
2836 // y shear
2837 y1 = (SplashCoord)ySign * y + yShear * x1;
2838 // this is a kludge: if yShear1 is negative, then (int)y1 would
2839 // change immediately after the first pixel, which is not what
2840 // we want
2841 if (yShear1 < 0) {
2842 y1 += 0.999;
2843 }
2844
2845 // loop-invariant constants
2846 n = yStep > 0 ? yStep : 1;
2847
2848 for (x = 0; x < scaledWidth; ++x) {
2849
2850 // x scale Bresenham
2851 xStep = xp;
2852 xt += xq;
2853 if (xt >= scaledWidth) {
2854 xt -= scaledWidth;
2855 ++xStep;
2856 }
2857
2858 // rotation
2859 if (rot) {
2860 x2 = (int)y1;
2861 y2 = -x1;
2862 } else {
2863 x2 = x1;
2864 y2 = (int)y1;
2865 }
2866
2867 // compute the filtered pixel at (x,y) after the x and y scaling
2868 // operations
2869 m = xStep > 0 ? xStep : 1;
2870 alphaAcc = 0;
2871 switch (srcMode) {
2872 case splashModeAMono8:
2873 p = pixBuf + xSrc * 2;
2874 pixAcc0 = 0;
2875 for (i = 0; i < n; ++i) {
2876 for (j = 0; j < m; ++j) {
2877 alphaAcc += *p++;
2878 pixAcc0 += *p++;
2879 }
2880 p += 2 * (w - m);
2881 }
2882 break;
2883 case splashModeARGB8:
2884 p = pixBuf + xSrc * 4;
2885 pixAcc0 = pixAcc1 = pixAcc2 = 0;
2886 for (i = 0; i < n; ++i) {
2887 for (j = 0; j < m; ++j) {
2888 alphaAcc += *p++;
2889 pixAcc0 += *p++;
2890 pixAcc1 += *p++;
2891 pixAcc2 += *p++;
2892 }
2893 p += 4 * (w - m);
2894 }
2895 break;
2896 case splashModeBGRA8:
2897 p = pixBuf + xSrc * 4;
2898 pixAcc0 = pixAcc1 = pixAcc2 = 0;
2899 for (i = 0; i < n; ++i) {
2900 for (j = 0; j < m; ++j) {
2901 pixAcc0 += *p++;
2902 pixAcc1 += *p++;
2903 pixAcc2 += *p++;
2904 alphaAcc += *p++;
2905 }
2906 p += 4 * (w - m);
2907 }
2908 break;
2909 #if SPLASH_CMYK
2910 case splashModeACMYK8:
2911 p = pixBuf + xSrc * 5;
2912 pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
2913 for (i = 0; i < n; ++i) {
2914 for (j = 0; j < m; ++j) {
2915 alphaAcc += *p++;
2916 pixAcc0 += *p++;
2917 pixAcc1 += *p++;
2918 pixAcc2 += *p++;
2919 pixAcc3 += *p++;
2920 }
2921 p += 5 * (w - m);
2922 }
2923 break;
2924 #endif
2925 default: // make gcc happy
2926 break;
2927 }
2928 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2929 alphaMul = pixMul * (1.0 / 256.0);
2930 alpha = (SplashCoord)alphaAcc * alphaMul;
2931
2932 if (alpha > 0) {
2933 // mono8 -> mono1 conversion, with halftoning
2934 if (halftone) {
2935 pix[0] = state->screen->test(tx + x2, ty + y2,
2936 (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0));
2937
2938 // no conversion, no halftoning
2939 } else {
2940 switch (bitmap->mode) {
2941 #if SPLASH_CMYK
2942 case splashModeCMYK8:
2943 pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
2944 // fall through
2945 #endif
2946 case splashModeRGB8:
2947 case splashModeBGR8:
2948 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2949 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2950 // fall through
2951 case splashModeMono1:
2952 case splashModeMono8:
2953 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2954 break;
2955 default: // make gcc happy
2956 break;
2957 }
2958 }
2959
2960 // set pixel
2961 drawPixel(tx + x2, ty + y2, pix, alpha * state->fillAlpha,
2962 clipRes2 == splashClipAllInside);
2963 }
2964
2965 // x scale Bresenham
2966 xSrc += xStep;
2967
2968 // x shear
2969 x1 += xSign;
2970
2971 // y shear
2972 y1 += yShear1;
2973 }
2974 }
2975
2976 } else {
2977
2978 // init y scale Bresenham
2979 yt = 0;
2980 lastYStep = 1;
2981
2982 for (y = 0; y < scaledHeight; ++y) {
2983
2984 // y scale Bresenham
2985 yStep = yp;
2986 yt += yq;
2987 if (yt >= scaledHeight) {
2988 yt -= scaledHeight;
2989 ++yStep;
2990 }
2991
2992 // read row(s) from image
2993 n = (yp > 0) ? yStep : lastYStep;
2994 if (n > 0) {
2995 p = pixBuf;
2996 for (i = 0; i < n; ++i) {
2997 (*src)(srcData, p);
2998 p += w * nComps;
2999 }
3000 }
3001 lastYStep = yStep;
3002
3003 // loop-invariant constants
3004 k1 = splashRound(xShear * ySign * y);
3005
3006 // clipping test
3007 if (clipRes != splashClipAllInside &&
3008 !rot &&
3009 (int)(yShear * k1) ==
3010 (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
3011 if (xSign > 0) {
3012 spanXMin = tx + k1;
3013 spanXMax = spanXMin + (scaledWidth - 1);
3014 } else {
3015 spanXMax = tx + k1;
3016 spanXMin = spanXMax - (scaledWidth - 1);
3017 }
3018 spanY = ty + ySign * y + (int)(yShear * k1);
3019 clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
3020 if (clipRes2 == splashClipAllOutside) {
3021 continue;
3022 }
3023 } else {
3024 clipRes2 = clipRes;
3025 }
3026
3027 // init x scale Bresenham
3028 xt = 0;
3029 xSrc = 0;
3030
3031 // x shear
3032 x1 = k1;
3033
3034 // y shear
3035 y1 = (SplashCoord)ySign * y + yShear * x1;
3036 // this is a kludge: if yShear1 is negative, then (int)y1 would
3037 // change immediately after the first pixel, which is not what
3038 // we want
3039 if (yShear1 < 0) {
3040 y1 += 0.999;
3041 }
3042
3043 // loop-invariant constants
3044 n = yStep > 0 ? yStep : 1;
3045
3046 for (x = 0; x < scaledWidth; ++x) {
3047
3048 // x scale Bresenham
3049 xStep = xp;
3050 xt += xq;
3051 if (xt >= scaledWidth) {
3052 xt -= scaledWidth;
3053 ++xStep;
3054 }
3055
3056 // rotation
3057 if (rot) {
3058 x2 = (int)y1;
3059 y2 = -x1;
3060 } else {
3061 x2 = x1;
3062 y2 = (int)y1;
3063 }
3064
3065 // compute the filtered pixel at (x,y) after the x and y scaling
3066 // operations
3067 m = xStep > 0 ? xStep : 1;
3068 switch (srcMode) {
3069 case splashModeMono1:
3070 case splashModeMono8:
3071 p = pixBuf + xSrc;
3072 pixAcc0 = 0;
3073 for (i = 0; i < n; ++i) {
3074 for (j = 0; j < m; ++j) {
3075 pixAcc0 += *p++;
3076 }
3077 p += w - m;
3078 }
3079 break;
3080 case splashModeRGB8:
3081 case splashModeBGR8:
3082 p = pixBuf + xSrc * 3;
3083 pixAcc0 = pixAcc1 = pixAcc2 = 0;
3084 for (i = 0; i < n; ++i) {
3085 for (j = 0; j < m; ++j) {
3086 pixAcc0 += *p++;
3087 pixAcc1 += *p++;
3088 pixAcc2 += *p++;
3089 }
3090 p += 3 * (w - m);
3091 }
3092 break;
3093 #if SPLASH_CMYK
3094 case splashModeCMYK8:
3095 p = pixBuf + xSrc * 4;
3096 pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
3097 for (i = 0; i < n; ++i) {
3098 for (j = 0; j < m; ++j) {
3099 pixAcc0 += *p++;
3100 pixAcc1 += *p++;
3101 pixAcc2 += *p++;
3102 pixAcc3 += *p++;
3103 }
3104 p += 4 * (w - m);
3105 }
3106 break;
3107 #endif
3108 default: // make gcc happy
3109 break;
3110 }
3111 pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
3112
3113 // mono8 -> mono1 conversion, with halftoning
3114 if (halftone) {
3115 pix[0] = state->screen->test(tx + x2, ty + y2,
3116 (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0));
3117
3118 // no conversion, no halftoning
3119 } else {
3120 switch (bitmap->mode) {
3121 #if SPLASH_CMYK
3122 case splashModeCMYK8:
3123 pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
3124 // fall through
3125 #endif
3126 case splashModeRGB8:
3127 case splashModeBGR8:
3128 pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
3129 pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
3130 // fall through
3131 case splashModeMono1:
3132 case splashModeMono8:
3133 pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
3134 break;
3135 default: // make gcc happy
3136 break;
3137 }
3138 }
3139
3140 // set pixel
3141 drawPixel(tx + x2, ty + y2, pix, state->fillAlpha,
3142 clipRes2 == splashClipAllInside);
3143
3144 // x scale Bresenham
3145 xSrc += xStep;
3146
3147 // x shear
3148 x1 += xSign;
3149
3150 // y shear
3151 y1 += yShear1;
3152 }
3153 }
3154
3155 }
3156
3157 gfree(pixBuf);
3158
3159 return splashOk;
3160 }
3161
3162 void Splash::dumpPath(SplashPath *path) {
3163 int i;
3164
3165 for (i = 0; i < path->length; ++i) {
3166 printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n",
3167 i, (double)path->pts[i].x, (double)path->pts[i].y,
3168 (path->flags[i] & splashPathFirst) ? " first" : "",
3169 (path->flags[i] & splashPathLast) ? " last" : "",
3170 (path->flags[i] & splashPathClosed) ? " closed" : "",
3171 (path->flags[i] & splashPathCurve) ? " curve" : "",
3172 (path->flags[i] & splashPathArcCW) ? " arcCW" : "");
3173 }
3174 }
3175
3176 void Splash::dumpXPath(SplashXPath *path) {
3177 int i;
3178
3179 for (i = 0; i < path->length; ++i) {
3180 printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
3181 i, (double)path->segs[i].x0, (double)path->segs[i].y0,
3182 (double)path->segs[i].x1, (double)path->segs[i].y1,
3183 (path->segs[i].flags & splashXPathFirst) ? "F" : " ",
3184 (path->segs[i].flags & splashXPathLast) ? "L" : " ",
3185 (path->segs[i].flags & splashXPathEnd0) ? "0" : " ",
3186 (path->segs[i].flags & splashXPathEnd1) ? "1" : " ",
3187 (path->segs[i].flags & splashXPathHoriz) ? "H" : " ",
3188 (path->segs[i].flags & splashXPathVert) ? "V" : " ",
3189 (path->segs[i].flags & splashXPathFlip) ? "P" : " ");
3190 }
3191 }