CairoOutputDev.cc 16 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
//========================================================================
//
// CairoOutputDev.cc
//
// Copyright 2003 Glyph & Cog, LLC
// Copyright 2004 Red Hat, Inc
//
//========================================================================

#include <config.h>

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

#include <string.h>
#include <math.h>
#include <cairo.h>

#include "goo/gfile.h"
#include "GlobalParams.h"
#include "Error.h"
#include "Object.h"
#include "GfxState.h"
#include "GfxFont.h"
#include "Link.h"
#include "CharCodeToUnicode.h"
#include "FontEncodingTables.h"
#include <fofi/FoFiTrueType.h>
#include <splash/SplashBitmap.h>
#include "CairoOutputDev.h"
#include "CairoFontEngine.h"

//------------------------------------------------------------------------

36
// #define LOG_CAIRO
Kristian Høgsberg's avatar
Kristian Høgsberg committed
37 38 39 40 41 42 43 44 45 46 47 48

#ifdef LOG_CAIRO
#define LOG(x) (x)
#else
#define LOG(x)
#endif


//------------------------------------------------------------------------
// CairoOutputDev
//------------------------------------------------------------------------

49
CairoOutputDev::CairoOutputDev() {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
50 51 52 53
  xref = NULL;

  FT_Init_FreeType(&ft_lib);
  fontEngine = NULL;
54
  glyphs = NULL;
55
  surface = NULL;
56 57
  fill_pattern = NULL;
  stroke_pattern = NULL;
58 59
  stroke_opacity = 1.0;
  fill_opacity = 1.0;
60
  textClipPath = NULL;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
61 62 63 64 65 66 67
}

CairoOutputDev::~CairoOutputDev() {
  if (fontEngine) {
    delete fontEngine;
  }
  FT_Done_FreeType(ft_lib);
68
  cairo_surface_destroy (surface);
69 70
  cairo_pattern_destroy (stroke_pattern);
  cairo_pattern_destroy (fill_pattern);
71
}
Kristian Høgsberg's avatar
Kristian Høgsberg committed
72

73 74 75 76 77
void CairoOutputDev::setSurface(cairo_surface_t *surface)
{
  cairo_surface_destroy (this->surface);
  cairo_surface_reference (surface);
  this->surface = surface;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
78 79 80 81 82 83 84 85 86 87 88
}

void CairoOutputDev::startDoc(XRef *xrefA) {
  xref = xrefA;
  if (fontEngine) {
    delete fontEngine;
  }
  fontEngine = new CairoFontEngine(ft_lib);
}

void CairoOutputDev::startPage(int pageNum, GfxState *state) {
89
  cairo = cairo_create (surface);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
90 91 92
}

void CairoOutputDev::endPage() {
93
  cairo_destroy (cairo);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
94 95 96 97 98 99 100 101 102 103 104 105 106
}

void CairoOutputDev::drawLink(Link *link, Catalog *catalog) {
}

void CairoOutputDev::saveState(GfxState *state) {
  LOG(printf ("save\n"));
  cairo_save (cairo);
}

void CairoOutputDev::restoreState(GfxState *state) {
  LOG(printf ("restore\n"));
  cairo_restore (cairo);
107 108 109 110 111 112 113

  /* These aren't restored by cairo_restore() since we keep them in
   * the output device. */
  updateFillColor(state);
  updateStrokeColor(state);
  updateFillOpacity(state);
  updateStrokeOpacity(state);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
114 115 116 117 118 119 120 121 122 123 124
}

void CairoOutputDev::updateAll(GfxState *state) {
  updateLineDash(state);
  updateLineJoin(state);
  updateLineCap(state);
  updateLineWidth(state);
  updateFlatness(state);
  updateMiterLimit(state);
  updateFillColor(state);
  updateStrokeColor(state);
125 126
  updateFillOpacity(state);
  updateStrokeOpacity(state);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
  needFontUpdate = gTrue;
}

void CairoOutputDev::updateCTM(GfxState *state, double m11, double m12,
				double m21, double m22,
				double m31, double m32) {
  updateLineDash(state);
  updateLineJoin(state);
  updateLineCap(state);
  updateLineWidth(state);
}

void CairoOutputDev::updateLineDash(GfxState *state) {
  double *dashPattern;
  int dashLength;
  double dashStart;
  double *transformedDash;
  double transformedStart;
  int i;

  state->getLineDash(&dashPattern, &dashLength, &dashStart);

  transformedDash = new double[dashLength];
  
  for (i = 0; i < dashLength; ++i) {
    transformedDash[i] =  state->transformWidth(dashPattern[i]);
  }
  transformedStart = state->transformWidth(dashStart);
  cairo_set_dash (cairo, transformedDash, dashLength, transformedStart);
  delete [] transformedDash;
}

void CairoOutputDev::updateFlatness(GfxState *state) {
160
  // cairo_set_tolerance (cairo, state->getFlatness());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

void CairoOutputDev::updateLineJoin(GfxState *state) {
  switch (state->getLineJoin()) {
  case 0:
    cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
    break;
  case 1:
    cairo_set_line_join (cairo, CAIRO_LINE_JOIN_ROUND);
    break;
  case 2:
    cairo_set_line_join (cairo, CAIRO_LINE_JOIN_BEVEL);
    break;
  }
}

void CairoOutputDev::updateLineCap(GfxState *state) {
  switch (state->getLineCap()) {
  case 0:
    cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT);
    break;
  case 1:
    cairo_set_line_cap (cairo, CAIRO_LINE_CAP_ROUND);
    break;
  case 2:
    cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE);
    break;
  }
}

void CairoOutputDev::updateMiterLimit(GfxState *state) {
  cairo_set_miter_limit (cairo, state->getMiterLimit());
}

void CairoOutputDev::updateLineWidth(GfxState *state) {
  LOG(printf ("line width: %f\n", state->getTransformedLineWidth()));
  cairo_set_line_width (cairo, state->getTransformedLineWidth());
}

void CairoOutputDev::updateFillColor(GfxState *state) {
  state->getFillRGB(&fill_color);
202 203 204 205 206 207 208 209 210

  cairo_pattern_destroy(fill_pattern);
  fill_pattern = cairo_pattern_create_rgba(fill_color.r / 65535.0,
					   fill_color.g / 65535.0,
					   fill_color.b / 65535.0,
					   fill_opacity);

  LOG(printf ("fill color: %d %d %d\n",
	      fill_color.r, fill_color.g, fill_color.b));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
211 212 213 214
}

void CairoOutputDev::updateStrokeColor(GfxState *state) {
  state->getStrokeRGB(&stroke_color);
215 216 217 218 219 220 221 222 223

  cairo_pattern_destroy(stroke_pattern);
  stroke_pattern = cairo_pattern_create_rgba(stroke_color.r / 65535.0,
					     stroke_color.g / 65535.0,
					     stroke_color.b / 65535.0,
					     stroke_opacity);
  
  LOG(printf ("stroke color: %d %d %d\n",
	      stroke_color.r, stroke_color.g, stroke_color.b));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
224 225
}

226 227
void CairoOutputDev::updateFillOpacity(GfxState *state) {
  fill_opacity = state->getFillOpacity();
228 229 230 231 232 233 234

  cairo_pattern_destroy(fill_pattern);
  fill_pattern = cairo_pattern_create_rgba(fill_color.r / 65535.0,
					   fill_color.g / 65535.0,
					   fill_color.b / 65535.0,
					   fill_opacity);

235 236 237 238 239
  LOG(printf ("fill opacity: %f\n", fill_opacity));
}

void CairoOutputDev::updateStrokeOpacity(GfxState *state) {
  stroke_opacity = state->getStrokeOpacity();
240 241 242 243 244 245 246

  cairo_pattern_destroy(stroke_pattern);
  stroke_pattern = cairo_pattern_create_rgba(stroke_color.r / 65535.0,
					     stroke_color.g / 65535.0,
					     stroke_color.b / 65535.0,
					     stroke_opacity);
  
247 248 249
  LOG(printf ("stroke opacity: %f\n", stroke_opacity));
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
250
void CairoOutputDev::updateFont(GfxState *state) {
251
  cairo_font_face_t *font_face;
252
  double m11, m12, m21, m22;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
253
  double w;
254
  cairo_matrix_t matrix;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
255 256

  LOG(printf ("updateFont() font=%s\n", state->getFont()->getName()->getCString()));
257

Kristian Høgsberg's avatar
Kristian Høgsberg committed
258 259
  needFontUpdate = gFalse;

260 261 262
  if (state->getFont()->getType() == fontType3)
    return;

263 264
  currentFont = fontEngine->getFont (state->getFont(), xref);

Kristian Høgsberg's avatar
Kristian Høgsberg committed
265 266 267 268
  state->getFontTransMat(&m11, &m12, &m21, &m22);
  m11 *= state->getHorizScaling();
  m12 *= state->getHorizScaling();

269
  LOG(printf ("font matrix: %f %f %f %f\n", m11, m12, m21, m22));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
270
  
271 272 273 274
  font_face = currentFont->getFontFace();
  cairo_set_font_face (cairo, font_face);

  matrix.xx = m11;
275 276 277
  matrix.xy = -m21;
  matrix.yx = m12;
  matrix.yy = -m22;
278 279 280
  matrix.x0 = 0;
  matrix.y0 = 0;
  cairo_set_font_matrix (cairo, &matrix);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
281 282
}

283
void CairoOutputDev::doPath(GfxState *state, GfxPath *path) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
284 285 286 287 288 289 290 291 292 293 294 295 296
  GfxSubpath *subpath;
  double x1, y1, x2, y2, x3, y3;
  int i, j;

  for (i = 0; i < path->getNumSubpaths(); ++i) {
    subpath = path->getSubpath(i);
    if (subpath->getNumPoints() > 0) {
      state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
      cairo_move_to (cairo, x1, y1);
      LOG (printf ("move_to %f, %f\n", x1, y1));
      j = 1;
      while (j < subpath->getNumPoints()) {
	if (subpath->getCurve(j)) {
297 298 299
	  state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
	  state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
	  state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	  cairo_curve_to (cairo, 
			  x1, y1,
			  x2, y2,
			  x3, y3);
	  LOG (printf ("curve_to %f, %f  %f, %f  %f, %f\n", x1, y1, x2, y2, x3, y3));
	  j += 3;
	} else {
	  state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
	  cairo_line_to (cairo, x1, y1);
	  LOG(printf ("line_to %f, %f\n", x1, y1));
	  ++j;
	}
      }
      if (subpath->isClosed()) {
	LOG (printf ("close\n"));
	cairo_close_path (cairo);
      }
    }
  }
}

void CairoOutputDev::stroke(GfxState *state) {
322
  doPath (state, state->getPath());
323
  cairo_set_source (cairo, stroke_pattern);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
324 325 326 327 328
  LOG(printf ("stroke\n"));
  cairo_stroke (cairo);
}

void CairoOutputDev::fill(GfxState *state) {
329
  doPath (state, state->getPath());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
330
  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
331
  cairo_set_source (cairo, fill_pattern);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
332 333 334 335 336
  LOG(printf ("fill\n"));
  cairo_fill (cairo);
}

void CairoOutputDev::eoFill(GfxState *state) {
337
  doPath (state, state->getPath());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
338
  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
339
  cairo_set_source (cairo, fill_pattern);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
340 341 342 343
  LOG(printf ("fill-eo\n"));
  cairo_fill (cairo);
}

344
void CairoOutputDev::clip(GfxState *state) {
345
  doPath (state, state->getPath());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
346 347 348 349 350 351
  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
  cairo_clip (cairo);
  LOG (printf ("clip\n"));
}

void CairoOutputDev::eoClip(GfxState *state) {
352
  doPath (state, state->getPath());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
353 354 355 356 357
  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
  cairo_clip (cairo);
  LOG (printf ("clip-eo\n"));
}

358
void CairoOutputDev::beginString(GfxState *state, GooString *s)
359 360
{
  int len = s->getLength();
361

362 363 364
  if (needFontUpdate)
    updateFont(state);

365 366 367 368 369 370 371
  glyphs = (cairo_glyph_t *) gmalloc (len * sizeof (cairo_glyph_t));
  glyphCount = 0;
}

void CairoOutputDev::drawChar(GfxState *state, double x, double y,
			      double dx, double dy,
			      double originX, double originY,
372
			      CharCode code, int nBytes, Unicode *u, int uLen)
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
{
  double tx, ty;

  glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen);
  state->transform(x, y, &tx, &ty);
  glyphs[glyphCount].x = tx;
  glyphs[glyphCount].y = ty;
  glyphCount++;
}

void CairoOutputDev::endString(GfxState *state)
{
  int render;

  if (!currentFont)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
388
    return;
389
   
390 391
  // ignore empty strings and invisible text -- this is used by
  // Acrobat Capture
Kristian Høgsberg's avatar
Kristian Høgsberg committed
392
  render = state->getRender();
393
  if (render == 3 || glyphCount == 0) {
394 395
    gfree(glyphs);
    glyphs = NULL;
396
    return;
397
  }
398
  
Kristian Høgsberg's avatar
Kristian Høgsberg committed
399
  if (!(render & 1)) {
400
    LOG (printf ("fill string\n"));
401
    cairo_set_source (cairo, fill_pattern);
402
    cairo_show_glyphs (cairo, glyphs, glyphCount);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
403
  }
404
  
Kristian Høgsberg's avatar
Kristian Høgsberg committed
405 406
  // stroke
  if ((render & 3) == 1 || (render & 3) == 2) {
407
    LOG (printf ("stroke string\n"));
408
    cairo_set_source (cairo, stroke_pattern);
409
    cairo_glyph_path (cairo, glyphs, glyphCount);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
410 411 412 413 414
    cairo_stroke (cairo);
  }

  // clip
  if (render & 4) {
415
    LOG (printf ("clip string\n"));
416 417 418 419 420 421 422 423 424
    // append the glyph path to textClipPath.

    // set textClipPath as the currentPath
    if (textClipPath) {
      cairo_append_path (cairo, textClipPath);
      cairo_path_destroy (textClipPath);
    }
    
    // append the glyph path
425
    cairo_glyph_path (cairo, glyphs, glyphCount);
426 427 428 429 430
   
    // move the path back into textClipPath 
    // and clear the current path
    textClipPath = cairo_copy_path (cairo);
    cairo_new_path (cairo);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
431
  }
432 433
  
  gfree (glyphs);
434
  glyphs = NULL;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
}

GBool CairoOutputDev::beginType3Char(GfxState *state, double x, double y,
				      double dx, double dy,
				      CharCode code, Unicode *u, int uLen) {
  return gFalse;
}

void CairoOutputDev::endType3Char(GfxState *state) {
}

void CairoOutputDev::type3D0(GfxState *state, double wx, double wy) {
}

void CairoOutputDev::type3D1(GfxState *state, double wx, double wy,
			      double llx, double lly, double urx, double ury) {
}

void CairoOutputDev::endTextObject(GfxState *state) {
454 455 456 457 458 459 460 461
  if (textClipPath) {
    // clip the accumulated text path
    cairo_append_path (cairo, textClipPath);
    cairo_clip (cairo);
    cairo_path_destroy (textClipPath);
    textClipPath = NULL;
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
462 463 464 465 466 467
}


void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
				    int width, int height, GBool invert,
				    GBool inlineImg) {
468 469
  unsigned char *buffer;
  unsigned char *dest;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
470
  cairo_surface_t *image;
471
  cairo_pattern_t *pattern;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
472 473
  int x, y;
  ImageStream *imgStr;
474
  Guchar *pix;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
475
  double *ctm;
476
  cairo_matrix_t matrix;
477
  int invert_bit;
478
  int row_stride;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
479

480 481
  row_stride = (width + 3) & ~3;
  buffer = (unsigned char *) malloc (height * row_stride);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
482 483 484 485 486 487
  if (buffer == NULL) {
    error(-1, "Unable to allocate memory for image.");
    return;
  }

  /* TODO: Do we want to cache these? */
488
  imgStr = new ImageStream(str, width, 1, 1);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
489 490
  imgStr->reset();

491 492
  invert_bit = invert ? 1 : 0;

Kristian Høgsberg's avatar
Kristian Høgsberg committed
493
  for (y = 0; y < height; y++) {
494
    pix = imgStr->getLine();
495
    dest = buffer + y * row_stride;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
496
    for (x = 0; x < width; x++) {
497 498

      if (pix[x] ^ invert_bit)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
499
	*dest++ = 0;
500 501
      else
	*dest++ = 255;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
502 503 504
    }
  }

505
  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
506
					       width, height, row_stride);
507 508 509 510 511
  if (image == NULL)
    return;
  pattern = cairo_pattern_create_for_surface (image);
  if (pattern == NULL)
    return;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
512 513 514

  ctm = state->getCTM();
  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
515 516
	       width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
  matrix.xx = ctm[0] / width;
517 518
  matrix.xy = -ctm[2] / height;
  matrix.yx = ctm[1] / width;
519 520 521 522 523
  matrix.yy = -ctm[3] / height;
  matrix.x0 = ctm[2] + ctm[4];
  matrix.y0 = ctm[3] + ctm[5];
  cairo_matrix_invert (&matrix);
  cairo_pattern_set_matrix (pattern, &matrix);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
524

525
  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
526
  /* FIXME: Doesn't the image mask support any colorspace? */
527
  cairo_set_source (cairo, fill_pattern);
528
  cairo_mask (cairo, pattern);
529

530
  cairo_pattern_destroy (pattern);
531 532
  cairo_surface_destroy (image);
  free (buffer);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
533 534 535 536 537 538
  delete imgStr;
}

void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
				int width, int height,
				GfxImageColorMap *colorMap,
539 540
				int *maskColors, GBool inlineImg)
{
541
  unsigned char *buffer;
542
  unsigned int *dest;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
543
  cairo_surface_t *image;
544
  cairo_pattern_t *pattern;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
545 546 547 548 549 550
  int x, y;
  ImageStream *imgStr;
  Guchar *pix;
  GfxRGB rgb;
  int alpha, i;
  double *ctm;
551
  cairo_matrix_t matrix;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
552 553
  int is_identity_transform;
  
554
  buffer = (unsigned char *)gmalloc (width * height * 4);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
555 556 557 558 559 560 561 562 563 564 565 566

  /* TODO: Do we want to cache these? */
  imgStr = new ImageStream(str, width,
			   colorMap->getNumPixelComps(),
			   colorMap->getBits());
  imgStr->reset();
  
  /* ICCBased color space doesn't do any color correction
   * so check its underlying color space as well */
  is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
		  colorMap->getColorSpace()->getMode() == csICCBased && 
		  ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB;
567 568 569 570 571 572 573 574

  if (maskColors) {
    for (y = 0; y < height; y++) {
      dest = (unsigned int *) (buffer + y * 4 * width);
      pix = imgStr->getLine();
      colorMap->getRGBLine (pix, dest, width);

      for (x = 0; x < width; x++) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
575
	for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
576 577 578 579
	  
	  if (pix[i] < maskColors[2*i] * 255||
	      pix[i] > maskColors[2*i+1] * 255) {
	    *dest = *dest | 0xff000000;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
580 581 582
	    break;
	  }
	}
583 584
	pix += colorMap->getNumPixelComps();
	dest++;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
585 586
      }
    }
587 588 589 590 591 592 593 594 595 596 597 598 599

    image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_ARGB32,
						 width, height, width * 4);
  }
  else {
    for (y = 0; y < height; y++) {
      dest = (unsigned int *) (buffer + y * 4 * width);
      pix = imgStr->getLine();
      colorMap->getRGBLine (pix, dest, width);
    }

    image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_RGB24,
						 width, height, width * 4);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
600 601
  }

602 603 604 605 606
  if (image == NULL)
    return;
  pattern = cairo_pattern_create_for_surface (image);
  if (pattern == NULL)
    return;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
607 608

  ctm = state->getCTM();
609 610 611
  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
	       width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
  matrix.xx = ctm[0] / width;
612 613
  matrix.xy = -ctm[2] / height;
  matrix.yx = ctm[1] / width;
614 615 616 617 618 619 620
  matrix.yy = -ctm[3] / height;
  matrix.x0 = ctm[2] + ctm[4];
  matrix.y0 = ctm[3] + ctm[5];

  cairo_matrix_invert (&matrix);
  cairo_pattern_set_matrix (pattern, &matrix);

621
  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR);
622 623
  cairo_set_source (cairo, pattern);
  cairo_paint (cairo);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
624

625
  cairo_pattern_destroy (pattern);
626 627
  cairo_surface_destroy (image);
  free (buffer);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
628 629
  delete imgStr;
}