CairoOutputDev.cc 15.5 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;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
58 59 60 61 62 63 64
}

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

70 71 72 73 74
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
75 76 77 78 79 80 81 82 83 84 85
}

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

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

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

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);
104 105 106 107 108 109 110

  /* 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
111 112 113 114 115 116 117 118 119 120 121
}

void CairoOutputDev::updateAll(GfxState *state) {
  updateLineDash(state);
  updateLineJoin(state);
  updateLineCap(state);
  updateLineWidth(state);
  updateFlatness(state);
  updateMiterLimit(state);
  updateFillColor(state);
  updateStrokeColor(state);
122 123
  updateFillOpacity(state);
  updateStrokeOpacity(state);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
124 125 126 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
  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) {
157
  // cairo_set_tolerance (cairo, state->getFlatness());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
158 159 160 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
}

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);
199 200 201 202 203 204 205 206 207

  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
208 209 210 211
}

void CairoOutputDev::updateStrokeColor(GfxState *state) {
  state->getStrokeRGB(&stroke_color);
212 213 214 215 216 217 218 219 220

  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
221 222
}

223 224
void CairoOutputDev::updateFillOpacity(GfxState *state) {
  fill_opacity = state->getFillOpacity();
225 226 227 228 229 230 231

  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);

232 233 234 235 236
  LOG(printf ("fill opacity: %f\n", fill_opacity));
}

void CairoOutputDev::updateStrokeOpacity(GfxState *state) {
  stroke_opacity = state->getStrokeOpacity();
237 238 239 240 241 242 243

  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);
  
244 245 246
  LOG(printf ("stroke opacity: %f\n", stroke_opacity));
}

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

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

257 258
  currentFont = fontEngine->getFont (state->getFont(), xref);

Kristian Høgsberg's avatar
Kristian Høgsberg committed
259 260 261 262
  state->getFontTransMat(&m11, &m12, &m21, &m22);
  m11 *= state->getHorizScaling();
  m12 *= state->getHorizScaling();

263
  LOG(printf ("font matrix: %f %f %f %f\n", m11, m12, m21, m22));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
264
  
265 266 267 268
  font_face = currentFont->getFontFace();
  cairo_set_font_face (cairo, font_face);

  matrix.xx = m11;
269 270 271
  matrix.xy = -m21;
  matrix.yx = m12;
  matrix.yy = -m22;
272 273 274
  matrix.x0 = 0;
  matrix.y0 = 0;
  cairo_set_font_matrix (cairo, &matrix);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
275 276
}

277
void CairoOutputDev::doPath(GfxState *state, GfxPath *path) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
278 279 280 281 282 283 284 285 286 287 288 289 290
  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)) {
291 292 293
	  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
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
	  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) {
316
  doPath (state, state->getPath());
317
  cairo_set_source (cairo, stroke_pattern);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
318 319 320 321 322
  LOG(printf ("stroke\n"));
  cairo_stroke (cairo);
}

void CairoOutputDev::fill(GfxState *state) {
323
  doPath (state, state->getPath());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
324
  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
325
  cairo_set_source (cairo, fill_pattern);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
326 327 328 329 330
  LOG(printf ("fill\n"));
  cairo_fill (cairo);
}

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

338
void CairoOutputDev::clip(GfxState *state) {
339
  doPath (state, state->getPath());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
340 341 342 343 344 345
  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
  cairo_clip (cairo);
  LOG (printf ("clip\n"));
}

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

352
void CairoOutputDev::beginString(GfxState *state, GooString *s)
353 354
{
  int len = s->getLength();
355

356 357 358
  if (needFontUpdate)
    updateFont(state);

359 360 361 362 363 364 365
  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,
366
			      CharCode code, int nBytes, Unicode *u, int uLen)
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
{
  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
382
    return;
383
   
384 385
  // ignore empty strings and invisible text -- this is used by
  // Acrobat Capture
Kristian Høgsberg's avatar
Kristian Høgsberg committed
386
  render = state->getRender();
387
  if (render == 3 || glyphCount == 0) {
388 389
    gfree(glyphs);
    glyphs = NULL;
390
    return;
391
  }
392
  
Kristian Høgsberg's avatar
Kristian Høgsberg committed
393
  if (!(render & 1)) {
394
    LOG (printf ("fill string\n"));
395
    cairo_set_source (cairo, fill_pattern);
396
    cairo_show_glyphs (cairo, glyphs, glyphCount);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
397
  }
398
  
Kristian Høgsberg's avatar
Kristian Høgsberg committed
399 400
  // stroke
  if ((render & 3) == 1 || (render & 3) == 2) {
401
    LOG (printf ("stroke string\n"));
402
    cairo_set_source (cairo, stroke_pattern);
403
    cairo_glyph_path (cairo, glyphs, glyphCount);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
404 405 406 407 408
    cairo_stroke (cairo);
  }

  // clip
  if (render & 4) {
409 410 411 412
    // FIXME: This is quite right yet, we need to accumulate all
    // glyphs within one text object before we clip.  Right now this
    // just add this one string.
    LOG (printf ("clip string\n"));
413
    cairo_glyph_path (cairo, glyphs, glyphCount);
414
    cairo_clip (cairo);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
415
  }
416 417
  
  gfree (glyphs);
418
  glyphs = NULL;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
}

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) {
}


void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
				    int width, int height, GBool invert,
				    GBool inlineImg) {
444 445
  unsigned char *buffer;
  unsigned char *dest;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
446
  cairo_surface_t *image;
447
  cairo_pattern_t *pattern;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
448 449
  int x, y;
  ImageStream *imgStr;
450
  Guchar *pix;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
451
  double *ctm;
452
  cairo_matrix_t matrix;
453
  int invert_bit;
454
  int row_stride;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
455

456 457
  row_stride = (width + 3) & ~3;
  buffer = (unsigned char *) malloc (height * row_stride);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
458 459 460 461 462 463
  if (buffer == NULL) {
    error(-1, "Unable to allocate memory for image.");
    return;
  }

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

467 468
  invert_bit = invert ? 1 : 0;

Kristian Høgsberg's avatar
Kristian Høgsberg committed
469
  for (y = 0; y < height; y++) {
470
    pix = imgStr->getLine();
471
    dest = buffer + y * row_stride;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
472
    for (x = 0; x < width; x++) {
473 474

      if (pix[x] ^ invert_bit)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
475
	*dest++ = 0;
476 477
      else
	*dest++ = 255;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
478 479 480
    }
  }

481
  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
482
					       width, height, row_stride);
483 484 485 486 487
  if (image == NULL)
    return;
  pattern = cairo_pattern_create_for_surface (image);
  if (pattern == NULL)
    return;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
488 489 490

  ctm = state->getCTM();
  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
491 492
	       width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
  matrix.xx = ctm[0] / width;
493 494
  matrix.xy = -ctm[2] / height;
  matrix.yx = ctm[1] / width;
495 496 497 498 499
  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
500

501
  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
502
  /* FIXME: Doesn't the image mask support any colorspace? */
503
  cairo_set_source (cairo, fill_pattern);
504
  cairo_mask (cairo, pattern);
505

506
  cairo_pattern_destroy (pattern);
507 508
  cairo_surface_destroy (image);
  free (buffer);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
509 510 511 512 513 514
  delete imgStr;
}

void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
				int width, int height,
				GfxImageColorMap *colorMap,
515 516
				int *maskColors, GBool inlineImg)
{
517
  unsigned char *buffer;
518
  unsigned int *dest;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
519
  cairo_surface_t *image;
520
  cairo_pattern_t *pattern;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
521 522 523 524 525 526
  int x, y;
  ImageStream *imgStr;
  Guchar *pix;
  GfxRGB rgb;
  int alpha, i;
  double *ctm;
527
  cairo_matrix_t matrix;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
528 529
  int is_identity_transform;
  
530
  buffer = (unsigned char *)gmalloc (width * height * 4);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
531 532 533 534 535 536 537 538 539 540 541 542

  /* 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;
543 544 545 546 547 548 549 550

  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
551
	for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
552 553 554 555
	  
	  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
556 557 558
	    break;
	  }
	}
559 560
	pix += colorMap->getNumPixelComps();
	dest++;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
561 562
      }
    }
563 564 565 566 567 568 569 570 571 572 573 574 575

    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
576 577
  }

578 579 580 581 582
  if (image == NULL)
    return;
  pattern = cairo_pattern_create_for_surface (image);
  if (pattern == NULL)
    return;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
583 584

  ctm = state->getCTM();
585 586 587
  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;
588 589
  matrix.xy = -ctm[2] / height;
  matrix.yx = ctm[1] / width;
590 591 592 593 594 595 596
  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);

597
  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR);
598 599
  cairo_set_source (cairo, pattern);
  cairo_paint (cairo);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
600

601
  cairo_pattern_destroy (pattern);
602 603
  cairo_surface_destroy (image);
  free (buffer);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
604 605
  delete imgStr;
}