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

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

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

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