~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/ipecanvas/ipecanvaspainter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2005-02-24 22:09:16 UTC
  • mfrom: (2.1.1 hoary)
  • Revision ID: james.westby@ubuntu.com-20050224220916-9vxiiqjz066r5489
Tags: 6.0pre23-2
debian/control: Ipe should depend on exact version of libipe.
Closes: #296771.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
*/
30
30
 
31
31
#include "ipetext.h"
 
32
#include "ipepdfparser.h"
32
33
 
33
34
#include "ipecanvas.h"
 
35
#include "ipefonts.h"
34
36
 
35
37
#include <qpainter.h>
36
38
#include <qpointarray.h>
55
57
 
56
58
// --------------------------------------------------------------------
57
59
 
 
60
class IpeRenderData : public IpeBitmap::MRenderData {
 
61
public:
 
62
  virtual ~IpeRenderData() { /* nothing */ }
 
63
  QImage iImage;
 
64
};
 
65
 
 
66
// --------------------------------------------------------------------
 
67
 
58
68
IpeCanvasPainter::IpeCanvasPainter(const IpeStyleSheet *sheet,
59
 
                                   IpeCanvasPaintServices *services,
 
69
                                   IpeCanvasFonts *fonts,
60
70
                                   QPixmap *pixmap, QPainter *painter,
61
 
                                   double zoom, bool pretty)
62
 
  : IpePainter(sheet), iServices(services),
63
 
    iPixmap(pixmap), iPainter(painter), iZoom(zoom), iPretty(pretty)
 
71
                                   double zoom, bool pretty,
 
72
                                   int maxBitmapSize)
 
73
  : IpePainter(sheet), iFonts(fonts),
 
74
    iPixmap(pixmap), iPainter(painter), iZoom(zoom), iPretty(pretty),
 
75
    iMaxBitmapSize(maxBitmapSize)
64
76
{
65
 
  assert(iServices);
66
77
  iDimmed = false;
67
78
  iPainter->setFont(QApplication::font());
 
79
  iFont = 0;
68
80
  // these symbolic dash styles are on fixed indices
69
81
  for (int i = 0; i < 4; ++i)
70
82
    iDash[i] =
71
83
      StyleSheet()->Find(IpeAttribute(IpeAttribute::EDashStyle, true, i+1));
72
84
}
73
85
 
74
 
void IpeCanvasPainter::BeginPath(const IpeVector &v)
75
 
{
76
 
  iV.push_back(QPt(Matrix() * v));
77
 
  iType.push_back(EBeginPath);
78
 
}
79
 
 
80
 
void IpeCanvasPainter::BeginClosedPath(const IpeVector &v)
81
 
{
82
 
  iV.push_back(QPt(Matrix() * v));
83
 
  iType.push_back(EBeginClosedPath);
84
 
}
85
 
 
86
 
void IpeCanvasPainter::LineTo(const IpeVector &v)
 
86
void IpeCanvasPainter::DoMoveTo(const IpeVector &v)
 
87
{
 
88
  if (iType.size() > 0 && iType.back() != EEndClosedPath)
 
89
    iType.push_back(EEndPath);
 
90
  iV.push_back(QPt(Matrix() * v));
 
91
  iType.push_back(EMoveTo);
 
92
}
 
93
 
 
94
void IpeCanvasPainter::DoLineTo(const IpeVector &v)
87
95
{
88
96
  iV.push_back(QPt(Matrix() * v));
89
97
  iType.push_back(ELineTo);
90
98
}
91
99
 
92
 
void IpeCanvasPainter::CurveTo(const IpeVector &v1, const IpeVector &v2,
93
 
                            const IpeVector &v3)
 
100
void IpeCanvasPainter::DoCurveTo(const IpeVector &v1, const IpeVector &v2,
 
101
                                 const IpeVector &v3)
94
102
{
95
103
  iV.push_back(QPt(Matrix() * v1));
96
104
  iV.push_back(QPt(Matrix() * v2));
98
106
  iType.push_back(ECurveTo);
99
107
}
100
108
 
101
 
void IpeCanvasPainter::EndPath()
102
 
{
103
 
  iType.push_back(EEndPath);
104
 
}
105
 
 
106
 
void IpeCanvasPainter::EndClosedPath()
 
109
void IpeCanvasPainter::DoClosePath()
107
110
{
108
111
  iType.push_back(EEndClosedPath);
109
112
}
110
113
 
111
 
void IpeCanvasPainter::DrawPath()
 
114
void IpeCanvasPainter::DoDrawPath()
112
115
{
 
116
  if (iType.size() > 0 && iType.back() != EEndClosedPath)
 
117
    iType.push_back(EEndPath);
 
118
 
113
119
  const IpeRepository *rep = StyleSheet()->Repository();
114
120
  // draw interior
115
121
  IpeAttribute fill = Fill();
141
147
 
142
148
    for (uint i = 0; i < iType.size(); ++i) {
143
149
      switch (iType[i]) {
144
 
      case EBeginPath:
145
 
      case EBeginClosedPath:
 
150
      case EMoveTo:
146
151
        org = iV[k];
 
152
        // fall through
147
153
      case ELineTo:
148
154
        pv.push_back(iV[k++]);
149
155
        break;
154
160
          ctrlPts.setPoint(1, iV[k++]);
155
161
          ctrlPts.setPoint(2, iV[k++]);
156
162
          ctrlPts.setPoint(3, iV[k++]);
157
 
#if QT_VERSION >= 300
 
163
#if QT_VERSION >= 0x030000
158
164
          QPointArray arr = ctrlPts.cubicBezier();
159
165
#else
160
166
          QPointArray arr = ctrlPts.quadBezier();
192
198
    // width
193
199
    if (LineWidth()) {
194
200
      assert(LineWidth().IsAbsolute());
195
 
      double wid = iZoom * rep->ToScalar(LineWidth());
 
201
      double wid = iZoom * rep->ToScalar(LineWidth()).ToDouble();
196
202
      pen.setWidth(uint(wid + 0.5));
197
203
    }
198
204
    // Exploit that Index() of null attribute is zero.
241
247
    uint k = 0;
242
248
    for (uint i = 0; i < iType.size(); ++i) {
243
249
      switch (iType[i]) {
244
 
      case EBeginPath:
245
 
      case EBeginClosedPath:
 
250
      case EMoveTo:
246
251
        org = iV[k];
 
252
        // fall through
247
253
      case ELineTo:
248
254
        pv.push_back(iV[k++]);
249
255
        break;
254
260
          ctrlPts.setPoint(1, iV[k++]);
255
261
          ctrlPts.setPoint(2, iV[k++]);
256
262
          ctrlPts.setPoint(3, iV[k++]);
257
 
#if QT_VERSION >= 300
 
263
#if QT_VERSION >= 0x030000
258
264
          QPointArray arr = ctrlPts.cubicBezier();
259
265
#else
260
266
          QPointArray arr = ctrlPts.quadBezier();
289
295
  iV.clear();
290
296
}
291
297
 
292
 
void IpeCanvasPainter::DrawBitmap(IpeBitmap bitmap)
 
298
void IpeCanvasPainter::DoDrawBitmap(IpeBitmap bitmap)
293
299
{
294
 
  if (!bitmap.RenderData())
295
 
    iServices->CvSvcSetRenderData(bitmap);
 
300
  if (!bitmap.RenderData()) {
 
301
    // todo: should we remember if this failed?
 
302
    IpeBuffer data = bitmap.PixelData();
 
303
    if (data.size() > 0) {
 
304
      IpeRenderData *render = new IpeRenderData;
 
305
      // warning: data buffer must remain alive as long as img is
 
306
      QImage img((uchar *) data.data(), bitmap.Width(), bitmap.Height(), 32,
 
307
                 0, 0, QImage::IgnoreEndian);
 
308
      if (img.width() > iMaxBitmapSize || img.height() > iMaxBitmapSize) {
 
309
        int wid = img.width();
 
310
        int ht = img.height();
 
311
        double factor;
 
312
        if (wid > ht)
 
313
          factor = wid / double(iMaxBitmapSize);
 
314
        else
 
315
          factor = ht / double(iMaxBitmapSize);
 
316
        wid = int(wid / factor + 0.5);
 
317
        ht = int(ht / factor + 0.5);
 
318
        render->iImage = img.smoothScale(wid, ht);
 
319
      } else
 
320
        render->iImage = img.copy();
 
321
      // img no longer needed
 
322
      bitmap.SetRenderData(render);
 
323
    }
 
324
  }
296
325
 
297
326
  if (bitmap.RenderData()) {
298
 
    QImage *qimg = static_cast<QImage *>(bitmap.RenderData());
299
 
    IpeMatrix tf = Matrix() * IpeMatrix(1.0 / qimg->width(), 0.0,
300
 
                                        0.0, -1.0 / qimg->height(),
 
327
    IpeRenderData *render = static_cast<IpeRenderData *>(bitmap.RenderData());
 
328
    IpeMatrix tf = Matrix() * IpeMatrix(1.0 / render->iImage.width(), 0.0,
 
329
                                        0.0, -1.0 / render->iImage.height(),
301
330
                                        0.0, 1.0);
302
331
    QWMatrix m;
303
332
    m.setMatrix(tf.iA[0], tf.iA[1], tf.iA[2], tf.iA[3], tf.iA[4], tf.iA[5]);
304
333
    iPainter->setWorldMatrix(m, true);
305
 
    iPainter->drawImage(0, 0, *qimg);
 
334
    iPainter->drawImage(0, 0, render->iImage);
306
335
    iPainter->resetXForm();
307
336
  }
308
337
}
309
338
 
310
 
void IpeCanvasPainter::DrawText(const IpeText *text)
 
339
void IpeCanvasPainter::DoDrawText(const IpeText *text)
311
340
{
312
341
  if (Stroke().IsNullOrVoid())
313
342
    return;
314
343
  // 'stroke' must be an absolute color
315
344
  assert(Stroke().IsAbsolute());
316
345
 
317
 
  IpeColor stroke = StyleSheet()->Repository()->ToColor(Stroke());
318
 
  QColor col(int(stroke.iRed * 255), int(stroke.iGreen * 255),
319
 
             int(stroke.iBlue * 255));
320
 
  if (iDimmed)
321
 
    col = col.light();
322
 
  QRgb rgb = col.rgb();
 
346
  // Current origin is lower left corner of text box
323
347
 
324
348
  // Draw bounding box rectangle
325
 
  if (!iPretty) {
 
349
  if (!iPretty && !iDimmed) {
326
350
    QPen pen;
327
351
    pen.setColor(Qt::green);
328
352
    pen.setStyle(Qt::DotLine);
342
366
 
343
367
  const IpeText::XForm *xf = text->GetXForm();
344
368
 
345
 
  if (!xf) {
 
369
  if (!xf || !iFonts) {
346
370
    QString s = QIpe(text->Text());
347
371
    uint olen = s.length();
348
372
    int i = s.find('\n');
351
375
    s.truncate(30);
352
376
    if (s.length() < olen)
353
377
      s += "...";
354
 
    iPainter->setPen(col);
 
378
 
 
379
    IpeColor stroke = StyleSheet()->Repository()->ToColor(Stroke());
 
380
    QColor col(int(stroke.iRed * 255), int(stroke.iGreen * 255),
 
381
               int(stroke.iBlue * 255));
 
382
    iPainter->setPen(iDimmed ? col.light() : col);
 
383
 
355
384
    // QRect r = iPainter->fontMetrics().boundingRect(s);
356
385
    QPoint pt = QPt(Matrix().Translation());
357
386
    pt.setY(pt.y() - iPainter->fontMetrics().descent());
358
387
    //if (text->IsMiniPage())
359
388
    //pt.setY(pt.y() + 15.0);
360
389
    iPainter->drawText(pt, s);
361
 
    return;
362
 
  }
363
 
 
364
 
  IpeMatrix m1 =
365
 
    Matrix() * IpeMatrix(xf->iStretch.iX, 0, 0, xf->iStretch.iY, 0, 0);
366
 
  for (IpeText::PdfCharSeq::const_iterator it = xf->iRender.begin();
367
 
       it != xf->iRender.end(); ++it) {
368
 
    IpeVector pos = m1 * it->iPos;
369
 
    QRgb cRgb = (it->iRgb == 0) ? rgb : it->iRgb;
370
 
    // compute world transformation
371
 
    IpeMatrix m = m1 * IpeLinear(it->iMatrix[0], it->iMatrix[1],
372
 
                                 it->iMatrix[2], it->iMatrix[3]);
373
 
    iServices->CvSvcRenderCharacter(iPixmap, it->iFontObject, m,
374
 
                               pos, cRgb, it->iCharCode, it->iUnicode);
375
 
  }
376
 
 
377
 
  for (IpeText::PdfSegSeq::const_iterator it = xf->iLines.begin();
378
 
       it != xf->iLines.end(); ++it) {
379
 
    QPen pen;
380
 
    QColor qstroke(QRgb(it->iRgb));
381
 
    pen.setColor(qstroke);
382
 
    double wid = iZoom * it->iWidth;
383
 
    pen.setWidth(uint(wid + 0.5));
384
 
    iPainter->setPen(pen);
385
 
    iPainter->moveTo(QPt(m1 * it->iSeg.iP));
386
 
    iPainter->lineTo(QPt(m1 * it->iSeg.iQ));
387
 
  }
 
390
  } else {
 
391
    Transform(IpeMatrix(xf->iStretch.iX, 0, 0, xf->iStretch.iY, 0, 0));
 
392
    Execute(xf->iStream);
 
393
  }
 
394
}
 
395
 
 
396
// --------------------------------------------------------------------
 
397
 
 
398
//! Clear PDF argument stack
 
399
void IpeCanvasPainter::ClearArgs()
 
400
{
 
401
  while (!iArgs.empty()) {
 
402
    delete iArgs.back();
 
403
    iArgs.pop_back();
 
404
  }
 
405
}
 
406
 
 
407
void IpeCanvasPainter::Execute(const IpeBuffer &buffer)
 
408
{
 
409
  IpeBufferSource source(buffer);
 
410
  IpePdfParser parser(source);
 
411
  iFont = 0;
 
412
  iFillRgb = 0x000000;
 
413
  iStrokeRgb = 0x000000;
 
414
  while (!parser.Eos()) {
 
415
    IpePdfToken tok = parser.Token();
 
416
    if (tok.iType != IpePdfToken::EOp) {
 
417
      const IpePdfObj *obj = parser.GetObject();
 
418
      if (!obj)
 
419
        break; // no further parsing attempted
 
420
      iArgs.push_back(obj);
 
421
    } else {
 
422
      // its an operator, execute it
 
423
      IpeString op = tok.iString;
 
424
      parser.GetToken();
 
425
      if (op == "cm")
 
426
        Opcm();
 
427
      else if (op == "Tf")
 
428
        OpTf();
 
429
      else if (op == "Td")
 
430
        OpTd();
 
431
      else if (op == "TJ")
 
432
        OpTJ();
 
433
      else if (op == "rg")
 
434
        Oprg(false);
 
435
      else if (op == "RG")
 
436
        Oprg(true);
 
437
      else if (op == "g")
 
438
        Opg(false);
 
439
      else if (op == "G")
 
440
        Opg(true);
 
441
      else if (op == "w")
 
442
        Opw();
 
443
      else if (op == "m")
 
444
        Opm();
 
445
      else if (op == "l")
 
446
        Opl();
 
447
      else if (op == "BT")
 
448
        OpBT();
 
449
      else if (op != "ET") {
 
450
        IpeString a;
 
451
        for (uint i = 0; i < iArgs.size(); ++i)
 
452
          a += iArgs[i]->Repr() + " ";
 
453
        ipeDebug("Op %s (%s)", op.CString(), a.CString());
 
454
      }
 
455
      ClearArgs();
 
456
    }
 
457
  }
 
458
  ClearArgs();
 
459
}
 
460
 
 
461
void IpeCanvasPainter::Opg(bool stroke)
 
462
{
 
463
  if (iArgs.size() != 1 || !iArgs[0]->Number())
 
464
    return;
 
465
  int gr = int(iArgs[0]->Number()->Value() * 255);
 
466
  if (stroke)
 
467
    iStrokeRgb = qRgb(gr, gr, gr);
 
468
  else
 
469
    iFillRgb = qRgb(gr, gr, gr);
 
470
}
 
471
 
 
472
 
 
473
void IpeCanvasPainter::Oprg(bool stroke)
 
474
{
 
475
  if (iArgs.size() != 3 || !iArgs[0]->Number() || !iArgs[1]->Number()
 
476
      || !iArgs[2]->Number())
 
477
    return;
 
478
  int r = int(iArgs[0]->Number()->Value() * 255);
 
479
  int g = int(iArgs[1]->Number()->Value() * 255);
 
480
  int b = int(iArgs[2]->Number()->Value() * 255);
 
481
  QColor col(r, g, b);
 
482
  if (iDimmed)
 
483
    col = col.light();
 
484
  if (stroke)
 
485
    iStrokeRgb = col.rgb();
 
486
  else
 
487
    iFillRgb = col.rgb();
 
488
}
 
489
 
 
490
void IpeCanvasPainter::Opcm()
 
491
{
 
492
  if (iArgs.size() != 6)
 
493
    return;
 
494
  IpeMatrix m;
 
495
  for (int i = 0; i < 6; ++i) {
 
496
    if (!iArgs[i]->Number())
 
497
      return;
 
498
    m.iA[i] = iArgs[i]->Number()->Value();
 
499
  }
 
500
  Transform(m);
 
501
}
 
502
 
 
503
void IpeCanvasPainter::Opw()
 
504
{
 
505
  if (iArgs.size() != 1 || !iArgs[0]->Number())
 
506
    return;
 
507
  iLineWid = iArgs[0]->Number()->Value();
 
508
 
 
509
}
 
510
 
 
511
void IpeCanvasPainter::Opm()
 
512
{
 
513
  if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
 
514
    return;
 
515
  IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
 
516
  iMoveTo = t;
 
517
}
 
518
 
 
519
void IpeCanvasPainter::Opl()
 
520
{
 
521
  if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
 
522
    return;
 
523
  IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
 
524
 
 
525
  QPen pen;
 
526
  pen.setColor(QRgb(iStrokeRgb));
 
527
  pen.setWidth(uint(iZoom * iLineWid + 0.5));
 
528
  iPainter->setPen(pen);
 
529
  iPainter->moveTo(QPt(Matrix() * iMoveTo));
 
530
  iPainter->lineTo(QPt(Matrix() * t));
 
531
}
 
532
 
 
533
void IpeCanvasPainter::OpBT()
 
534
{
 
535
  iFont = 0;
 
536
  iTextPos = IpeVector::Zero;
 
537
}
 
538
 
 
539
void IpeCanvasPainter::OpTf()
 
540
{
 
541
  if (iArgs.size() != 2 || !iArgs[0]->Name() || !iArgs[1]->Number())
 
542
    return;
 
543
  IpeString name = iArgs[0]->Name()->Value();
 
544
  iFontSize = iArgs[1]->Number()->Value();
 
545
  if (name[0] != 'F')
 
546
    return;
 
547
  int font = IpeLex(name.substr(1)).GetInt();
 
548
  // ipeDebug("Setting font %d at %g", font, iFontSize);
 
549
  IpeLinear m = Matrix().Linear() * IpeLinear(iFontSize, 0, 0, iFontSize);
 
550
  iFont = iFonts->GetSize(font, m);
 
551
}
 
552
 
 
553
void IpeCanvasPainter::OpTd()
 
554
{
 
555
  if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
 
556
    return;
 
557
  IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
 
558
  iTextPos = iTextPos + t;
 
559
}
 
560
 
 
561
void IpeCanvasPainter::OpTJ()
 
562
{
 
563
  if (!iFont || iArgs.size() != 1 || !iArgs[0]->Array())
 
564
    return;
 
565
  IpeVector pos = iTextPos;
 
566
  for (int i = 0; i < iArgs[0]->Array()->Count(); ++i) {
 
567
    const IpePdfObj *obj = iArgs[0]->Array()->Obj(i, 0);
 
568
    if (obj->Number()) {
 
569
      pos.iX -= 0.001 * iFontSize * obj->Number()->Value();
 
570
    } else if (obj->String()) {
 
571
      IpeString s = obj->String()->Value();
 
572
      for (int j = 0; j < s.size(); ++j) {
 
573
        uchar ch = s[j];
 
574
        QPoint pt = QPt(Matrix() * pos);
 
575
        DrawChar(ch, iFillRgb, pt.x(), pt.y());
 
576
        pos.iX += 0.001 * iFontSize * iFont->Face()->Width(ch);
 
577
      }
 
578
    }
 
579
  }
 
580
}
 
581
 
 
582
// --------------------------------------------------------------------
 
583
 
 
584
//! Draw a glyph.
 
585
/*! Glyph is drawn with hotspot at position (x,y) (on the pixmap) */
 
586
bool IpeCanvasPainter::DrawChar(int ch, QRgb rgb, int x, int y)
 
587
{
 
588
  if (!iFont)
 
589
    return false;
 
590
 
 
591
  int w = iPixmap->width();
 
592
  int h = iPixmap->height();
 
593
 
 
594
  // generate the glyph pixmap
 
595
  int xOffset, yOffset, gw, gh;
 
596
  uchar *p = iFont->GetGlyph(ch, xOffset, yOffset, gw, gh);
 
597
  if (!p)
 
598
    return false;
 
599
 
 
600
  // compute: (x0,y0) = position in destination pixmap
 
601
  //          (x1,y1) = position in glyph image
 
602
  //          (w0,h0) = size of image transfer
 
603
  int x0, y0, x1, y1, w0, h0;
 
604
  x0 = x - xOffset;
 
605
  y0 = y - yOffset;
 
606
  x1 = 0;
 
607
  y1 = 0;
 
608
  w0 = gw;
 
609
  h0 = gh;
 
610
  if (x0 < 0) {
 
611
    x1 = -x0;
 
612
    w0 += x0;
 
613
    x0 = 0;
 
614
  }
 
615
  if (x0 + w0 > w)
 
616
    w0 = w - x0;
 
617
  if (w0 < 0)
 
618
    return true;
 
619
  if (y0 < 0) {
 
620
    y1 = -y0;
 
621
    h0 += y0;
 
622
    y0 = 0;
 
623
  }
 
624
  if (y0 + h0 > h)
 
625
    h0 = h - y0;
 
626
  if (h0 < 0)
 
627
    return true;
 
628
 
 
629
  QPixmap dst(gw, gh);
 
630
  bitBlt(&dst, x1, y1, iPixmap, x0, y0, w0, h0);
 
631
  QImage image = dst.convertToImage();
 
632
 
 
633
  if (iFonts->AntiAlias()) {
 
634
    int r = qRed(rgb);
 
635
    int g = qGreen(rgb);
 
636
    int b = qBlue(rgb);
 
637
    // stuff the glyph pixmap into the image
 
638
    for (int yy = 0; yy < gh; ++yy) {
 
639
      uint *dst = (uint *) image.scanLine(yy);
 
640
      for (int xx = 0; xx < gw; ++xx) {
 
641
        int pix = *p++ & 0xff;
 
642
        int pix1 = 0xff - pix;
 
643
        if (pix > 0) {
 
644
          uint bg = *dst;
 
645
          int newr = (pix * r + pix1 * qRed(bg)) / 255;
 
646
          int newg = (pix * g + pix1 * qGreen(bg)) / 255;
 
647
          int newb = (pix * b + pix1 * qBlue(bg)) / 255;
 
648
          *dst = qRgb(newr, newg, newb);
 
649
        }
 
650
        ++dst;
 
651
      }
 
652
    }
 
653
  } else {
 
654
    // one color
 
655
    for (int yy = 0; yy < gh; ++yy) {
 
656
      uint *dst = (uint *) image.scanLine(yy);
 
657
      for (int xx = 0; xx < gw; xx += 8) {
 
658
        int pix = *p++;
 
659
        for (int xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
 
660
          if (pix & 0x80)
 
661
            *dst = rgb;
 
662
          pix <<= 1;
 
663
          ++dst;
 
664
        }
 
665
      }
 
666
    }
 
667
  }
 
668
  dst.convertFromImage(image);
 
669
  bitBlt(iPixmap, x0, y0, &dst, x1, y1, w0, h0);
 
670
  return true;
388
671
}
389
672
 
390
673
// --------------------------------------------------------------------