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