source: trunk/poppler/mypoppler/splash/Splash.cc @ 44

Last change on this file since 44 was 44, checked in by Eugene Romanenko, 15 years ago

poppler updated to version 0.5.3, related changes

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