~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: 2009-12-11 21:22:35 UTC
  • mfrom: (4.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20091211212235-5iio4nzpra64snab
Tags: 7.0.10-1
* New upstream.  Closes: #551192.
  - New build-depends: libcairo2-dev, liblua5.1-0-dev, gsfonts
  - patches/config.diff: Remove.  Upstream build system replaced.
  - Runtime lib package changed to libipe7.0.10 from libipe1c2a
  - Devel package renamed to libipe-dev (from libipe1-dev)
  - Package ipe depends on lua5.1 due to ipe-update-master.

* rules: Re-write to use dh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// --------------------------------------------------------------------
2
 
// Canvas Painter
3
 
// --------------------------------------------------------------------
4
 
/*
5
 
 
6
 
    This file is part of the extensible drawing editor Ipe.
7
 
    Copyright (C) 1993-2007  Otfried Cheong
8
 
 
9
 
    Ipe is free software; you can redistribute it and/or modify it
10
 
    under the terms of the GNU General Public License as published by
11
 
    the Free Software Foundation; either version 2 of the License, or
12
 
    (at your option) any later version.
13
 
 
14
 
    As a special exception, you have permission to link Ipe with the
15
 
    CGAL library and distribute executables, as long as you follow the
16
 
    requirements of the Gnu General Public License in regard to all of
17
 
    the software in the executable aside from CGAL.
18
 
 
19
 
    Ipe is distributed in the hope that it will be useful, but WITHOUT
20
 
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21
 
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22
 
    License for more details.
23
 
 
24
 
    You should have received a copy of the GNU General Public License
25
 
    along with Ipe; if not, you can find it at
26
 
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
27
 
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28
 
 
29
 
*/
30
 
 
31
 
#include "ipetext.h"
32
 
#include "ipepdfparser.h"
33
 
#include "ipecanvas.h"
34
 
#include "ipecanvaspainter.h"
35
 
#include "ipefonts.h"
36
 
 
37
 
#include <QPainter>
38
 
#include <QImage>
39
 
#include <QPaintDevice>
40
 
#include <QApplication>
41
 
#include <QPixmap>
42
 
#include <QPainterPath>
43
 
 
44
 
// What a mess is Windows!
45
 
#ifdef GetObject
46
 
#undef GetObject
47
 
#endif
48
 
 
49
 
inline QPointF QPt(const IpeVector &v)
50
 
{
51
 
  return QPointF(v.iX, v.iY);
52
 
}
53
 
 
54
 
inline IpeString IpeQ(const QString &str)
55
 
{
56
 
  return IpeString(str.toUtf8());
57
 
}
58
 
 
59
 
inline QString QIpe(const IpeString &str)
60
 
{
61
 
  return QString::fromUtf8(str.CString());
62
 
}
63
 
 
64
 
// --------------------------------------------------------------------
65
 
 
66
 
class IpeRenderData : public IpeBitmap::MRenderData {
67
 
public:
68
 
  virtual ~IpeRenderData() { /* Nothing */ }
69
 
  QImage iImage;
70
 
};
71
 
 
72
 
// --------------------------------------------------------------------
73
 
 
74
 
IpeCanvasPainter::IpeCanvasPainter(const IpeStyleSheet *sheet,
75
 
                                   IpeCanvasFonts *fonts, QPainter *painter,
76
 
                                   double zoom, bool pretty,
77
 
                                   int maxBitmapSize)
78
 
  : IpePainter(sheet), iFonts(fonts),
79
 
    iPainter(painter), iZoom(zoom), iPretty(pretty),
80
 
    iMaxBitmapSize(maxBitmapSize)
81
 
{
82
 
  iDimmed = false;
83
 
  iPainter->setFont(QApplication::font());
84
 
  iFont = 0;
85
 
  // these symbolic dash styles are on fixed indices
86
 
  for (int i = 0; i < 4; ++i)
87
 
    iDash[i] =
88
 
      StyleSheet()->Find(IpeAttribute(IpeAttribute::EDashStyle, true, i+1));
89
 
}
90
 
 
91
 
void IpeCanvasPainter::DoMoveTo(const IpeVector &v)
92
 
{
93
 
  if (iType.size() > 0 && iType.back() != EEndClosedPath)
94
 
    iType.push_back(EEndPath);
95
 
  iV.push_back(QPt(Matrix() * v));
96
 
  iType.push_back(EMoveTo);
97
 
}
98
 
 
99
 
void IpeCanvasPainter::DoLineTo(const IpeVector &v)
100
 
{
101
 
  iV.push_back(QPt(Matrix() * v));
102
 
  iType.push_back(ELineTo);
103
 
}
104
 
 
105
 
void IpeCanvasPainter::DoCurveTo(const IpeVector &v1, const IpeVector &v2,
106
 
                                 const IpeVector &v3)
107
 
{
108
 
  iV.push_back(QPt(Matrix() * v1));
109
 
  iV.push_back(QPt(Matrix() * v2));
110
 
  iV.push_back(QPt(Matrix() * v3));
111
 
  iType.push_back(ECurveTo);
112
 
}
113
 
 
114
 
void IpeCanvasPainter::DoClosePath()
115
 
{
116
 
  iType.push_back(EEndClosedPath);
117
 
}
118
 
 
119
 
void IpeCanvasPainter::DoDrawPath()
120
 
{
121
 
  if (iType.size() > 0 && iType.back() != EEndClosedPath)
122
 
    iType.push_back(EEndPath);
123
 
 
124
 
  const IpeRepository *rep = StyleSheet()->Repository();
125
 
 
126
 
  // build path object
127
 
  QPainterPath path;
128
 
  uint k = 0;
129
 
  for (uint i = 0; i < iType.size(); ++i) {
130
 
    switch (iType[i]) {
131
 
    case EMoveTo:
132
 
      path.moveTo(iV[k++]);
133
 
      break;
134
 
    case ELineTo:
135
 
      path.lineTo(iV[k++]);
136
 
      break;
137
 
    case ECurveTo:
138
 
      path.cubicTo(iV[k], iV[k+1], iV[k+2]);
139
 
      k += 3;
140
 
      break;
141
 
    case EEndPath:
142
 
      break;
143
 
    case EEndClosedPath:
144
 
      path.closeSubpath();
145
 
      break;
146
 
    }
147
 
  }
148
 
  IpeAttribute windRule = WindRule();
149
 
  if (!windRule)
150
 
    windRule = StyleSheet()->WindRule();
151
 
  Qt::FillRule wind = (windRule.Index() != 0) ?
152
 
    Qt::WindingFill : Qt::OddEvenFill;
153
 
  path.setFillRule(wind);
154
 
 
155
 
  // clear path
156
 
  iType.clear();
157
 
  iV.clear();
158
 
 
159
 
  IpeAttribute fill = Fill();
160
 
  IpeAttribute stroke = Stroke();
161
 
  IpeAttribute dash = DashStyle();
162
 
 
163
 
  // nothing to draw?
164
 
  if (fill.IsNullOrVoid() && dash.IsVoid())
165
 
    return;
166
 
 
167
 
  if (!fill.IsNullOrVoid()) {
168
 
    assert(fill.IsAbsolute());
169
 
    IpeColor fillColor = rep->ToColor(fill);
170
 
    QColor qfill(int(fillColor.iRed * 255),
171
 
                 int(fillColor.iGreen * 255),
172
 
                 int(fillColor.iBlue * 255));
173
 
    QBrush brush;
174
 
    DimColor(qfill);
175
 
    brush.setColor(qfill);
176
 
    brush.setStyle(Qt::SolidPattern);
177
 
    iPainter->setBrush(brush);
178
 
  } else
179
 
    iPainter->setBrush(Qt::NoBrush);
180
 
 
181
 
  if (!dash.IsVoid() && !stroke.IsNull()) {
182
 
    assert(stroke.IsAbsolute());
183
 
    IpeColor strokeColor = rep->ToColor(stroke);
184
 
    QPen pen;
185
 
    QColor qstroke(int(strokeColor.iRed * 255),
186
 
                   int(strokeColor.iGreen * 255),
187
 
                   int(strokeColor.iBlue * 255));
188
 
    DimColor(qstroke);
189
 
    pen.setColor(qstroke);
190
 
    // width
191
 
    if (LineWidth()) {
192
 
      assert(LineWidth().IsAbsolute());
193
 
      double wid = iZoom * rep->ToScalar(LineWidth()).ToDouble();
194
 
      pen.setWidth(uint(wid + 0.5));
195
 
    }
196
 
    IpeAttribute join = LineJoin();
197
 
    if (!join)
198
 
      join = StyleSheet()->LineJoin();
199
 
    switch (join.Index()) {
200
 
    case IpeStrokeStyle::EMiterJoin:
201
 
      pen.setJoinStyle(Qt::MiterJoin);
202
 
      break;
203
 
    case IpeStrokeStyle::ERoundJoin:
204
 
      pen.setJoinStyle(Qt::RoundJoin);
205
 
      break;
206
 
    case IpeStrokeStyle::EBevelJoin:
207
 
      pen.setJoinStyle(Qt::BevelJoin);
208
 
      break;
209
 
    }
210
 
    IpeAttribute cap = LineCap();
211
 
    if (!cap)
212
 
      cap = StyleSheet()->LineCap();
213
 
    switch (cap.Index()) {
214
 
    case IpeStrokeStyle::EButtCap:
215
 
      pen.setCapStyle(Qt::FlatCap);
216
 
      break;
217
 
    case IpeStrokeStyle::ERoundCap:
218
 
      pen.setCapStyle(Qt::RoundCap);
219
 
      break;
220
 
    case IpeStrokeStyle::ESquareCap:
221
 
      pen.setCapStyle(Qt::SquareCap);
222
 
      break;
223
 
    }
224
 
    if (!dash.IsNullOrSolid()) {
225
 
      // now comes the tricky part
226
 
      if (dash == iDash[0])
227
 
        pen.setStyle(Qt::DashLine);
228
 
      else if (dash == iDash[1])
229
 
        pen.setStyle(Qt::DotLine);
230
 
      else if (dash == iDash[2])
231
 
        pen.setStyle(Qt::DashDotLine);
232
 
      else if (dash == iDash[3])
233
 
        pen.setStyle(Qt::DashDotDotLine);
234
 
      else
235
 
        pen.setStyle(Qt::DotLine);
236
 
    }
237
 
    iPainter->setPen(pen);
238
 
  } else
239
 
    iPainter->setPen(Qt::NoPen);
240
 
 
241
 
  iPainter->drawPath(path);
242
 
}
243
 
 
244
 
void IpeCanvasPainter::DoDrawBitmap(IpeBitmap bitmap)
245
 
{
246
 
  if (!bitmap.RenderData()) {
247
 
    // todo: should we remember if this failed?
248
 
    IpeBuffer data = bitmap.PixelData();
249
 
    if (data.size() > 0) {
250
 
      IpeRenderData *render = new IpeRenderData;
251
 
      // warning: data buffer must remain alive as long as img is
252
 
      QImage img((uchar *) data.data(), bitmap.Width(), bitmap.Height(),
253
 
                 QImage::Format_RGB32);
254
 
      if (img.width() > iMaxBitmapSize || img.height() > iMaxBitmapSize) {
255
 
        int wid = img.width();
256
 
        int ht = img.height();
257
 
        double factor;
258
 
        if (wid > ht)
259
 
          factor = wid / double(iMaxBitmapSize);
260
 
        else
261
 
          factor = ht / double(iMaxBitmapSize);
262
 
        wid = int(wid / factor + 0.5);
263
 
        ht = int(ht / factor + 0.5);
264
 
        render->iImage = img.scaled(wid, ht, Qt::KeepAspectRatio,
265
 
                                    Qt::FastTransformation);
266
 
      } else
267
 
        render->iImage = img.copy();
268
 
      // img no longer needed
269
 
      bitmap.SetRenderData(render);
270
 
    }
271
 
  }
272
 
 
273
 
  if (bitmap.RenderData()) {
274
 
    IpeRenderData *render = static_cast<IpeRenderData *>(bitmap.RenderData());
275
 
    IpeMatrix tf = Matrix() * IpeMatrix(1.0 / render->iImage.width(), 0.0,
276
 
                                        0.0, -1.0 / render->iImage.height(),
277
 
                                        0.0, 1.0);
278
 
    QMatrix m;
279
 
    m.setMatrix(tf.iA[0], tf.iA[1], tf.iA[2], tf.iA[3], tf.iA[4], tf.iA[5]);
280
 
    iPainter->setMatrix(m);
281
 
    iPainter->drawImage(0, 0, render->iImage);
282
 
    iPainter->resetMatrix();
283
 
  }
284
 
}
285
 
 
286
 
void IpeCanvasPainter::DoDrawText(const IpeText *text)
287
 
{
288
 
  // Current origin is lower left corner of text box
289
 
 
290
 
  // Draw bounding box rectangle
291
 
  if (!iPretty && !iDimmed && !text->isInternal()) {
292
 
    QPen pen;
293
 
    pen.setColor(Qt::green);
294
 
    pen.setStyle(Qt::DotLine);
295
 
    iPainter->setPen(pen);
296
 
    iPainter->setBrush(Qt::NoBrush);
297
 
    QPolygonF poly;
298
 
    poly.append(QPt(Matrix() * IpeVector(0,0)));
299
 
    poly.append(QPt(Matrix() * IpeVector(0, text->TotalHeight())));
300
 
    poly.append(QPt(Matrix() * IpeVector(text->Width(), text->TotalHeight())));
301
 
    poly.append(QPt(Matrix() * IpeVector(text->Width(), 0)));
302
 
    iPainter->drawConvexPolygon(poly);
303
 
    iPainter->setPen(Qt::NoPen);
304
 
    iPainter->setBrush(Qt::green);
305
 
    QPointF ref = QPt(Matrix() * text->Align());
306
 
    QRectF r(ref.x() - 3, ref.y() - 3, 6, 6);
307
 
    iPainter->drawRect(r);
308
 
  }
309
 
 
310
 
  IpeAttribute str = Stroke();
311
 
  if (str.IsNull()) str = IpeAttribute::Black();
312
 
  assert(str.IsAbsolute());
313
 
  IpeColor stroke = StyleSheet()->Repository()->ToColor(str);
314
 
  QColor col(int(stroke.iRed * 255), int(stroke.iGreen * 255),
315
 
             int(stroke.iBlue * 255));
316
 
  DimColor(col);
317
 
 
318
 
  const IpeText::XForm *xf = text->getXForm();
319
 
  if (!xf || !iFonts) {
320
 
    if (!text->isInternal()) {
321
 
      QString s = QIpe(text->Text());
322
 
      int olen = s.length();
323
 
      int i = s.indexOf(QLatin1Char('\n'));
324
 
      if (i >= 0)
325
 
        s.truncate(i);
326
 
      s.truncate(30);
327
 
      if (s.length() < olen)
328
 
        s += QLatin1String("...");
329
 
 
330
 
      QPointF pt = QPt(Matrix().Translation());
331
 
      pt.setY(pt.y() - iPainter->fontMetrics().descent());
332
 
      iPainter->setPen(col);
333
 
      iPainter->drawText(pt, s);
334
 
    }
335
 
  } else {
336
 
    iTextRgb = col.rgb();
337
 
    Transform(IpeMatrix(xf->iStretch, 0, 0, xf->iStretch, 0, 0));
338
 
    Execute(xf->iStream);
339
 
  }
340
 
}
341
 
 
342
 
// --------------------------------------------------------------------
343
 
 
344
 
//! If dimming, replace color by dimmed version.
345
 
void IpeCanvasPainter::DimColor(QColor &col)
346
 
{
347
 
  if (iDimmed) {
348
 
    int h, s, v;
349
 
    col.getHsv(&h, &s, &v);
350
 
    v += 150;
351
 
    if (v > 255)
352
 
      col = col.light(175);
353
 
    else
354
 
      col.setHsv(h, s, v);
355
 
  }
356
 
}
357
 
 
358
 
// --------------------------------------------------------------------
359
 
 
360
 
//! Clear PDF argument stack
361
 
void IpeCanvasPainter::ClearArgs()
362
 
{
363
 
  while (!iArgs.empty()) {
364
 
    delete iArgs.back();
365
 
    iArgs.pop_back();
366
 
  }
367
 
}
368
 
 
369
 
void IpeCanvasPainter::Execute(const IpeBuffer &buffer)
370
 
{
371
 
  IpeBufferSource source(buffer);
372
 
  IpePdfParser parser(source);
373
 
  iFont = 0;
374
 
  iFillRgb = 0x000000;
375
 
  iStrokeRgb = 0x000000;
376
 
  while (!parser.Eos()) {
377
 
    IpePdfToken tok = parser.Token();
378
 
    if (tok.iType != IpePdfToken::EOp) {
379
 
      const IpePdfObj *obj = parser.GetObject();
380
 
      if (!obj)
381
 
        break; // no further parsing attempted
382
 
      iArgs.push_back(obj);
383
 
    } else {
384
 
      // its an operator, execute it
385
 
      IpeString op = tok.iString;
386
 
      parser.GetToken();
387
 
      if (op == "cm")
388
 
        Opcm();
389
 
      else if (op == "q")
390
 
        Opq();
391
 
      else if (op == "Q")
392
 
        OpQ();
393
 
      else if (op == "Tf")
394
 
        OpTf();
395
 
      else if (op == "Td")
396
 
        OpTd();
397
 
      else if (op == "TJ")
398
 
        OpTJ();
399
 
      else if (op == "rg")
400
 
        Oprg(false);
401
 
      else if (op == "RG")
402
 
        Oprg(true);
403
 
      else if (op == "g")
404
 
        Opg(false);
405
 
      else if (op == "G")
406
 
        Opg(true);
407
 
      else if (op == "k")
408
 
        Opk(false);
409
 
      else if (op == "K")
410
 
        Opk(true);
411
 
      else if (op == "w")
412
 
        Opw();
413
 
      else if (op == "m")
414
 
        Opm();
415
 
      else if (op == "l")
416
 
        Opl();
417
 
      else if (op == "re")
418
 
        Opre();
419
 
      else if (op == "BT")
420
 
        OpBT();
421
 
      else if (op != "ET") {
422
 
        IpeString a;
423
 
        for (uint i = 0; i < iArgs.size(); ++i)
424
 
          a += iArgs[i]->Repr() + " ";
425
 
        ipeDebug("Op %s (%s)", op.CString(), a.CString());
426
 
      }
427
 
      ClearArgs();
428
 
    }
429
 
  }
430
 
  ClearArgs();
431
 
}
432
 
 
433
 
void IpeCanvasPainter::Opg(bool stroke)
434
 
{
435
 
  if (iArgs.size() != 1 || !iArgs[0]->Number())
436
 
    return;
437
 
  int gr = int(iArgs[0]->Number()->Value() * 255);
438
 
  if (stroke)
439
 
    iStrokeRgb = qRgb(gr, gr, gr);
440
 
  else
441
 
    iFillRgb = qRgb(gr, gr, gr);
442
 
}
443
 
 
444
 
void IpeCanvasPainter::Opre()
445
 
{
446
 
  if (iArgs.size() != 4 || !iArgs[0]->Number() || !iArgs[1]->Number()
447
 
      || !iArgs[2]->Number() || !iArgs[3]->Number())
448
 
    return;
449
 
 
450
 
  // The 3rd/4th argument is the size of the rectangle 
451
 
  IpeVector ll(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
452
 
  IpeVector wh(iArgs[2]->Number()->Value(), iArgs[3]->Number()->Value());
453
 
 
454
 
  QBrush brush;
455
 
  brush.setStyle(Qt::SolidPattern);
456
 
  brush.setColor(QRgb(iFillRgb));
457
 
  iPainter->setBrush(brush);
458
 
  QPen pen(Qt::NoPen); // no stroke
459
 
  iPainter->setPen(pen);
460
 
  QPointF p = QPt(Matrix() * ll);
461
 
  QPointF q = QPt(Matrix().Linear() * wh);
462
 
  iPainter->drawRect(QRectF(p.x(), p.y(), q.x(), q.y()));
463
 
}
464
 
 
465
 
void IpeCanvasPainter::Oprg(bool stroke)
466
 
{
467
 
  if (iArgs.size() != 3 || !iArgs[0]->Number() || !iArgs[1]->Number()
468
 
      || !iArgs[2]->Number())
469
 
    return;
470
 
  int r = int(iArgs[0]->Number()->Value() * 255);
471
 
  int g = int(iArgs[1]->Number()->Value() * 255);
472
 
  int b = int(iArgs[2]->Number()->Value() * 255);
473
 
  QColor col(r, g, b);
474
 
  DimColor(col);
475
 
  if (stroke)
476
 
    iStrokeRgb = col.rgb();
477
 
  else
478
 
    iFillRgb = col.rgb();
479
 
}
480
 
 
481
 
void IpeCanvasPainter::Opk(bool stroke)
482
 
{
483
 
  if (iArgs.size() != 4 || !iArgs[0]->Number() || !iArgs[1]->Number()
484
 
      || !iArgs[2]->Number() || !iArgs[3]->Number())
485
 
    return;
486
 
  // ignore values, but use text object stroke color
487
 
  if (stroke)
488
 
    iStrokeRgb = iTextRgb;
489
 
  else
490
 
    iFillRgb = iTextRgb;
491
 
}
492
 
 
493
 
void IpeCanvasPainter::Opcm()
494
 
{
495
 
  if (iArgs.size() != 6)
496
 
    return;
497
 
  IpeMatrix m;
498
 
  for (int i = 0; i < 6; ++i) {
499
 
    if (!iArgs[i]->Number())
500
 
      return;
501
 
    m.iA[i] = iArgs[i]->Number()->Value();
502
 
  }
503
 
  Transform(m);
504
 
}
505
 
 
506
 
void IpeCanvasPainter::Opw()
507
 
{
508
 
  if (iArgs.size() != 1 || !iArgs[0]->Number())
509
 
    return;
510
 
  iLineWid = iArgs[0]->Number()->Value();
511
 
 
512
 
}
513
 
 
514
 
void IpeCanvasPainter::Opq()
515
 
{
516
 
  if (iArgs.size() != 0)
517
 
    return;
518
 
  Push();
519
 
}
520
 
 
521
 
void IpeCanvasPainter::OpQ()
522
 
{
523
 
  if (iArgs.size() != 0)
524
 
    return;
525
 
  Pop();
526
 
}
527
 
 
528
 
void IpeCanvasPainter::Opm()
529
 
{
530
 
  if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
531
 
    return;
532
 
  IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
533
 
  iMoveTo = t;
534
 
}
535
 
 
536
 
void IpeCanvasPainter::Opl()
537
 
{
538
 
  if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
539
 
    return;
540
 
  IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
541
 
 
542
 
  QPen pen;
543
 
  pen.setColor(QRgb(iStrokeRgb));
544
 
  pen.setWidth(uint(iZoom * iLineWid + 0.5));
545
 
  iPainter->setPen(pen);
546
 
  iPainter->drawLine(QPt(Matrix() * iMoveTo), QPt(Matrix() * t));
547
 
}
548
 
 
549
 
void IpeCanvasPainter::OpBT()
550
 
{
551
 
  iFont = 0;
552
 
  iTextPos = iTextLinePos = IpeVector::Zero;
553
 
}
554
 
 
555
 
void IpeCanvasPainter::OpTf()
556
 
{
557
 
  if (iArgs.size() != 2 || !iArgs[0]->Name() || !iArgs[1]->Number())
558
 
    return;
559
 
  IpeString name = iArgs[0]->Name()->Value();
560
 
  iFontSize = iArgs[1]->Number()->Value();
561
 
  if (name[0] != 'F')
562
 
    return;
563
 
  int font = IpeLex(name.substr(1)).GetInt();
564
 
  // ipeDebug("Setting font %d at %g", font, iFontSize);
565
 
  IpeLinear m = Matrix().Linear() * IpeLinear(iFontSize, 0, 0, iFontSize);
566
 
  iFont = iFonts->GetSize(font, m);
567
 
}
568
 
 
569
 
void IpeCanvasPainter::OpTd()
570
 
{
571
 
  if (iArgs.size() != 2 || !iArgs[0]->Number() || !iArgs[1]->Number())
572
 
    return;
573
 
  IpeVector t(iArgs[0]->Number()->Value(), iArgs[1]->Number()->Value());
574
 
  iTextPos = iTextLinePos = iTextLinePos + t;
575
 
}
576
 
 
577
 
void IpeCanvasPainter::OpTJ()
578
 
{
579
 
  if (!iFont || iArgs.size() != 1 || !iArgs[0]->Array())
580
 
    return;
581
 
  for (int i = 0; i < iArgs[0]->Array()->Count(); ++i) {
582
 
    const IpePdfObj *obj = iArgs[0]->Array()->Obj(i, 0);
583
 
    if (obj->Number()) {
584
 
      iTextPos.iX -= 0.001 * iFontSize * obj->Number()->Value();
585
 
    } else if (obj->String()) {
586
 
      IpeString s = obj->String()->Value();
587
 
      for (int j = 0; j < s.size(); ++j) {
588
 
        uchar ch = s[j];
589
 
        IpeVector pt = Matrix() * iTextPos;
590
 
        DrawChar(ch, iFillRgb, int(pt.iX + 0.5), int(pt.iY + 0.5));
591
 
        iTextPos.iX += 0.001 * iFontSize * iFont->Face()->Width(ch);
592
 
      }
593
 
    }
594
 
  }
595
 
}
596
 
 
597
 
// --------------------------------------------------------------------
598
 
 
599
 
//! Draw a glyph.
600
 
/*! Glyph is drawn with hotspot at position (x,y) (on the pixmap) */
601
 
bool IpeCanvasPainter::DrawChar(int ch, QRgb rgb, int x, int y)
602
 
{
603
 
  if (!iFont)
604
 
    return false;
605
 
 
606
 
  // generate the glyph pixmap
607
 
 
608
 
  int xOffset, yOffset, gw, gh;
609
 
  uchar *p = iFont->GetGlyph(ch, xOffset, yOffset, gw, gh);
610
 
  if (!p)
611
 
    return false;
612
 
 
613
 
  QImage image(gw, gh, QImage::Format_ARGB32);
614
 
 
615
 
  if (iFonts->AntiAlias()) {
616
 
    rgb &= 0x00ffffff; // take out alpha
617
 
    for (int yy = 0; yy < gh; ++yy) {
618
 
      uint *dst = (uint *) image.scanLine(yy);
619
 
      for (int xx = 0; xx < gw; ++xx) {
620
 
        uint pix = (*p++ & 0xff) << 24;
621
 
        *dst++ = pix | rgb;
622
 
      }
623
 
    }
624
 
  } else {
625
 
    image.fill(0x00ffffff);
626
 
    rgb = 0xff000000 | rgb;
627
 
    // one color
628
 
    for (int yy = 0; yy < gh; ++yy) {
629
 
      uint *dst = (uint *) image.scanLine(yy);
630
 
      for (int xx = 0; xx < gw; xx += 8) {
631
 
        int pix = *p++;
632
 
        for (int xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
633
 
          if (pix & 0x80)
634
 
            *dst = rgb;
635
 
          pix <<= 1;
636
 
          ++dst;
637
 
        }
638
 
      }
639
 
    }
640
 
  }
641
 
  iPainter->drawImage(x - xOffset, y - yOffset, image);
642
 
  return true;
643
 
}
644
 
 
645
 
// --------------------------------------------------------------------