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

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

First import

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